1use k256::{
4 ecdsa::{
5 signature::{
6 hazmat::{PrehashSigner, PrehashVerifier},
7 Signer, Verifier,
8 },
9 Signature, SigningKey, VerifyingKey,
10 },
11 elliptic_curve::{
12 self,
13 ecdh::diffie_hellman,
14 sec1::{Coordinates, FromEncodedPoint, ToEncodedPoint},
15 },
16 EncodedPoint, PublicKey, SecretKey,
17};
18use subtle::ConstantTimeEq;
19
20use super::{ec_common, EcCurves, HasKeyAlg, HasKeyBackend, KeyAlg};
21use crate::{
22 buffer::{ArrayKey, WriteBuffer},
23 error::Error,
24 generic_array::typenum::{U32, U33, U65},
25 jwk::{FromJwk, JwkEncoder, JwkParts, ToJwk},
26 kdf::KeyExchange,
27 random::KeyMaterial,
28 repr::{KeyGen, KeyMeta, KeyPublicBytes, KeySecretBytes, KeypairBytes, KeypairMeta},
29 sign::{KeySigVerify, KeySign, SignatureType},
30};
31
32pub const ES256K_SIGNATURE_LENGTH: usize = 64;
42
43pub const PUBLIC_KEY_LENGTH: usize = 33;
45pub const SECRET_KEY_LENGTH: usize = 32;
47pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH;
49
50pub const JWK_KEY_TYPE: &str = "EC";
52pub const JWK_CURVE: &str = "secp256k1";
54
55type FieldSize = elliptic_curve::FieldBytesSize<k256::Secp256k1>;
56
57#[derive(Clone, Debug)]
59pub struct K256KeyPair {
60 secret: Option<SecretKey>,
62 public: PublicKey,
63}
64
65impl K256KeyPair {
66 #[inline]
67 pub(crate) fn from_secret_key(sk: SecretKey) -> Self {
68 let pk = sk.public_key();
69 Self {
70 secret: Some(sk),
71 public: pk,
72 }
73 }
74
75 pub(crate) fn check_public_bytes(&self, pk: &[u8]) -> Result<(), Error> {
76 if self.with_public_bytes(|slf| slf.ct_eq(pk)).into() {
77 Ok(())
78 } else {
79 Err(err_msg!(InvalidKeyData, "invalid k256 keypair"))
80 }
81 }
82
83 pub(crate) fn to_signing_key(&self) -> Option<SigningKey> {
84 self.secret.as_ref().map(SigningKey::from)
85 }
86
87 pub fn sign(&self, message: &[u8]) -> Option<[u8; ES256K_SIGNATURE_LENGTH]> {
89 if let Some(skey) = self.to_signing_key() {
90 let sig: Signature = skey.sign(message);
91 let sigb: [u8; 64] = sig.to_bytes().into();
92 Some(sigb)
93 } else {
94 None
95 }
96 }
97
98 pub fn sign_prehashed(&self, hashed_message: &[u8]) -> Option<[u8; ES256K_SIGNATURE_LENGTH]> {
100 if let Some(skey) = self.to_signing_key() {
101 if let Ok(sig) = PrehashSigner::<Signature>::sign_prehash(&skey, hashed_message) {
102 let sigb: [u8; 64] = sig.to_bytes().into();
103 return Some(sigb);
104 }
105 }
106 None
107 }
108
109 pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
111 if let Ok(sig) = Signature::try_from(signature) {
112 let vk = VerifyingKey::from(&self.public);
113 vk.verify(message, &sig).is_ok()
114 } else {
115 false
116 }
117 }
118
119 pub fn verify_signature_prehashed(&self, hashed_message: &[u8], signature: &[u8]) -> bool {
121 if let Ok(sig) = Signature::try_from(signature) {
122 let vk = VerifyingKey::from(&self.public);
123 vk.verify_prehash(hashed_message, &sig).is_ok()
124 } else {
125 false
126 }
127 }
128}
129
130impl HasKeyBackend for K256KeyPair {}
131
132impl HasKeyAlg for K256KeyPair {
133 fn algorithm(&self) -> KeyAlg {
134 KeyAlg::EcCurve(EcCurves::Secp256k1)
135 }
136}
137
138impl KeyMeta for K256KeyPair {
139 type KeySize = U32;
140}
141
142impl KeyGen for K256KeyPair {
143 fn generate(mut rng: impl KeyMaterial) -> Result<Self, Error> {
144 ArrayKey::<FieldSize>::temp(|buf| loop {
145 rng.read_okm(buf);
146 if let Ok(key) = SecretKey::from_bytes(buf) {
147 return Ok(Self::from_secret_key(key));
148 }
149 })
150 }
151}
152
153impl KeySecretBytes for K256KeyPair {
154 fn from_secret_bytes(key: &[u8]) -> Result<Self, Error> {
155 if key.len() == SECRET_KEY_LENGTH {
156 if let Ok(sk) = SecretKey::from_bytes(key.into()) {
157 return Ok(Self::from_secret_key(sk));
158 }
159 }
160 Err(err_msg!(InvalidKeyData))
161 }
162
163 fn with_secret_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
164 if let Some(sk) = self.secret.as_ref() {
165 ArrayKey::<FieldSize>::temp(|arr| {
166 ec_common::write_sk(sk, &mut arr[..]);
167 f(Some(arr))
168 })
169 } else {
170 f(None)
171 }
172 }
173}
174
175impl KeypairMeta for K256KeyPair {
176 type PublicKeySize = U33;
177 type KeypairSize = U65;
178}
179
180impl KeypairBytes for K256KeyPair {
181 fn from_keypair_bytes(kp: &[u8]) -> Result<Self, Error> {
182 if kp.len() != KEYPAIR_LENGTH {
183 return Err(err_msg!(InvalidKeyData));
184 }
185 let result = K256KeyPair::from_secret_bytes(&kp[..SECRET_KEY_LENGTH])
186 .map_err(|_| err_msg!(InvalidKeyData))?;
187 result.check_public_bytes(&kp[SECRET_KEY_LENGTH..])?;
188 Ok(result)
189 }
190
191 fn with_keypair_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
192 if let Some(sk) = self.secret.as_ref() {
193 ArrayKey::<<Self as KeypairMeta>::KeypairSize>::temp(|arr| {
194 ec_common::write_sk(sk, &mut arr[..SECRET_KEY_LENGTH]);
195 let pk_enc = self.public.to_encoded_point(true);
196 arr[SECRET_KEY_LENGTH..].copy_from_slice(pk_enc.as_bytes());
197 f(Some(&*arr))
198 })
199 } else {
200 f(None)
201 }
202 }
203}
204
205impl KeyPublicBytes for K256KeyPair {
206 fn from_public_bytes(key: &[u8]) -> Result<Self, Error> {
207 let pk = PublicKey::from_sec1_bytes(key).map_err(|_| err_msg!(InvalidKeyData))?;
208 Ok(Self {
209 secret: None,
210 public: pk,
211 })
212 }
213
214 fn with_public_bytes<O>(&self, f: impl FnOnce(&[u8]) -> O) -> O {
215 f(self.public.to_encoded_point(true).as_bytes())
216 }
217}
218
219impl KeySign for K256KeyPair {
220 fn write_signature(
221 &self,
222 message: &[u8],
223 sig_type: Option<SignatureType>,
224 out: &mut dyn WriteBuffer,
225 ) -> Result<(), Error> {
226 match sig_type {
227 None | Some(SignatureType::ES256K) => {
228 if let Some(sig) = self.sign(message) {
229 out.buffer_write(&sig[..])?;
230 Ok(())
231 } else {
232 Err(err_msg!(Unsupported, "Signing operation not supported"))
233 }
234 }
235 Some(SignatureType::ES256Kph) => {
236 if let Some(sig) = self.sign_prehashed(message) {
237 out.buffer_write(&sig[..])?;
238 Ok(())
239 } else {
240 Err(err_msg!(Unsupported, "Signing operation not supported"))
241 }
242 }
243 #[allow(unreachable_patterns)]
244 _ => Err(err_msg!(Unsupported, "Unsupported signature type")),
245 }
246 }
247}
248
249impl KeySigVerify for K256KeyPair {
250 fn verify_signature(
251 &self,
252 message: &[u8],
253 signature: &[u8],
254 sig_type: Option<SignatureType>,
255 ) -> Result<bool, Error> {
256 match sig_type {
257 None | Some(SignatureType::ES256K) => Ok(self.verify_signature(message, signature)),
258 Some(SignatureType::ES256Kph) => {
259 Ok(self.verify_signature_prehashed(message, signature))
260 }
261 #[allow(unreachable_patterns)]
262 _ => Err(err_msg!(Unsupported, "Unsupported signature type")),
263 }
264 }
265}
266
267impl ToJwk for K256KeyPair {
268 fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
269 let pk_enc = self.public.to_encoded_point(false);
270 let (x, y) = match pk_enc.coordinates() {
271 Coordinates::Identity => {
272 return Err(err_msg!(
273 Unsupported,
274 "Cannot convert identity point to JWK"
275 ))
276 }
277 Coordinates::Uncompressed { x, y } => (x, y),
278 Coordinates::Compressed { .. } | Coordinates::Compact { .. } => unreachable!(),
279 };
280
281 enc.add_str("crv", JWK_CURVE)?;
282 enc.add_str("kty", JWK_KEY_TYPE)?;
283 enc.add_as_base64("x", &x[..])?;
284 enc.add_as_base64("y", &y[..])?;
285 if enc.is_secret() {
286 self.with_secret_bytes(|buf| {
287 if let Some(sk) = buf {
288 enc.add_as_base64("d", sk)
289 } else {
290 Ok(())
291 }
292 })?;
293 }
294 Ok(())
295 }
296}
297
298impl FromJwk for K256KeyPair {
299 fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
300 if jwk.kty != JWK_KEY_TYPE {
301 return Err(err_msg!(InvalidKeyData, "Unsupported key type"));
302 }
303 if jwk.crv != JWK_CURVE {
304 return Err(err_msg!(InvalidKeyData, "Unsupported key algorithm"));
305 }
306 let pk_x = ArrayKey::<FieldSize>::try_new_with(|arr| {
307 if jwk.x.decode_base64(arr)? != arr.len() {
308 Err(err_msg!(InvalidKeyData))
309 } else {
310 Ok(())
311 }
312 })?;
313 let pk_y = ArrayKey::<FieldSize>::try_new_with(|arr| {
314 if jwk.y.decode_base64(arr)? != arr.len() {
315 Err(err_msg!(InvalidKeyData))
316 } else {
317 Ok(())
318 }
319 })?;
320 let pk = Option::from(PublicKey::from_encoded_point(
321 &EncodedPoint::from_affine_coordinates(pk_x.as_ref(), pk_y.as_ref(), false),
322 ))
323 .ok_or_else(|| err_msg!(InvalidKeyData))?;
324 if jwk.d.is_some() {
325 ArrayKey::<FieldSize>::temp(|arr| {
326 if jwk.d.decode_base64(arr)? != arr.len() {
327 Err(err_msg!(InvalidKeyData))
328 } else {
329 let kp = K256KeyPair::from_secret_bytes(arr)?;
330 if kp.public != pk {
331 Err(err_msg!(InvalidKeyData))
332 } else {
333 Ok(kp)
334 }
335 }
336 })
337 } else {
338 Ok(Self {
339 secret: None,
340 public: pk,
341 })
342 }
343 }
344}
345
346impl KeyExchange for K256KeyPair {
347 fn write_key_exchange(&self, other: &Self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
348 match self.secret.as_ref() {
349 Some(sk) => {
350 let xk = diffie_hellman(sk.to_nonzero_scalar(), other.public.as_affine());
351 out.buffer_write(xk.raw_secret_bytes().as_ref())?;
352 Ok(())
353 }
354 None => Err(err_msg!(MissingSecretKey)),
355 }
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use base64::Engine;
362 use sha2::Digest;
363
364 use super::*;
365 use crate::repr::ToPublicBytes;
366
367 #[test]
368 fn jwk_expected() {
369 let test_pvt_b64 = "rhYFsBPF9q3-uZThy7B3c4LDF_8wnozFUAEm5LLC4Zw";
379 let test_pub_b64 = (
380 "dWCvM4fTdeM0KmloF57zxtBPXTOythHPMm1HCLrdd3A",
381 "36uMVGM7hnw-N6GnjFcihWE3SkrhMLzzLCdPMXPEXlA",
382 );
383 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
384 .decode(test_pvt_b64)
385 .unwrap();
386 let sk = K256KeyPair::from_secret_bytes(&test_pvt).expect("Error creating signing key");
387
388 let jwk = sk.to_jwk_public(None).expect("Error converting key to JWK");
389 let jwk = JwkParts::try_from_str(&jwk).expect("Error parsing JWK");
390 assert_eq!(jwk.kty, JWK_KEY_TYPE);
391 assert_eq!(jwk.crv, JWK_CURVE);
392 assert_eq!(jwk.x, test_pub_b64.0);
393 assert_eq!(jwk.y, test_pub_b64.1);
394 assert_eq!(jwk.d, None);
395 let pk_load = K256KeyPair::from_jwk_parts(jwk).unwrap();
396 assert_eq!(sk.to_public_bytes(), pk_load.to_public_bytes());
397
398 let jwk = sk.to_jwk_secret(None).expect("Error converting key to JWK");
399 let jwk = JwkParts::from_slice(&jwk).expect("Error parsing JWK");
400 assert_eq!(jwk.kty, JWK_KEY_TYPE);
401 assert_eq!(jwk.crv, JWK_CURVE);
402 assert_eq!(jwk.x, test_pub_b64.0);
403 assert_eq!(jwk.y, test_pub_b64.1);
404 assert_eq!(jwk.d, test_pvt_b64);
405 let sk_load = K256KeyPair::from_jwk_parts(jwk).unwrap();
406 assert_eq!(
407 sk.to_keypair_bytes().unwrap(),
408 sk_load.to_keypair_bytes().unwrap()
409 );
410 }
411
412 #[test]
413 fn sign_verify_expected() {
414 let test_msg = b"This is a dummy message for use with tests";
415 let test_sig = &hex!(
416 "a2a3affbe18cda8c5a7b6375f05b304c2303ab8beb21428709a43a519f8f946f
417 6ffa7966afdb337e9b1f70bb575282e71d4fe5bbe6bfa97b229d6bd7e97df1e5"
418 );
419 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
420 .decode("jv_VrhPomm6_WOzb74xF4eMI0hu9p0W1Zlxi0nz8AFs")
421 .unwrap();
422 let kp = K256KeyPair::from_secret_bytes(&test_pvt).unwrap();
423 let sig = kp.sign(&test_msg[..]).unwrap();
424 assert_eq!(sig, &test_sig[..]);
425 assert!(kp.verify_signature(&test_msg[..], &sig[..]));
426 assert!(!kp.verify_signature(b"Not the message", &sig[..]));
427 assert!(!kp.verify_signature(&test_msg[..], &[0u8; 64]));
428 }
429
430 #[test]
431 fn sign_verify_expected_prehash() {
432 let test_msg = sha2::Sha256::digest(b"This is a dummy message for use with tests");
433 let test_sig = &hex!(
434 "a2a3affbe18cda8c5a7b6375f05b304c2303ab8beb21428709a43a519f8f946f
435 6ffa7966afdb337e9b1f70bb575282e71d4fe5bbe6bfa97b229d6bd7e97df1e5"
436 );
437 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
438 .decode("jv_VrhPomm6_WOzb74xF4eMI0hu9p0W1Zlxi0nz8AFs")
439 .unwrap();
440 let kp = K256KeyPair::from_secret_bytes(&test_pvt).unwrap();
441 let sig = kp.sign_prehashed(&test_msg[..]).unwrap();
442 assert_eq!(sig, &test_sig[..]);
443 assert!(kp.verify_signature_prehashed(&test_msg[..], &sig[..]));
444 assert!(!kp.verify_signature_prehashed(b"Not the message", &sig[..]));
445 assert!(!kp.verify_signature_prehashed(&test_msg[..], &[0u8; 64]));
446 }
447
448 #[test]
449 fn key_exchange_random() {
450 let kp1 = K256KeyPair::random().unwrap();
451 let kp2 = K256KeyPair::random().unwrap();
452 assert_ne!(
453 kp1.to_keypair_bytes().unwrap(),
454 kp2.to_keypair_bytes().unwrap()
455 );
456
457 let xch1 = kp1.key_exchange_bytes(&kp2).unwrap();
458 let xch2 = kp2.key_exchange_bytes(&kp1).unwrap();
459 assert_eq!(xch1.len(), 32);
460 assert_eq!(xch1, xch2);
461 }
462
463 #[test]
464 fn round_trip_bytes() {
465 let kp = K256KeyPair::random().unwrap();
466 let cmp = K256KeyPair::from_keypair_bytes(&kp.to_keypair_bytes().unwrap()).unwrap();
467 assert_eq!(
468 kp.to_keypair_bytes().unwrap(),
469 cmp.to_keypair_bytes().unwrap()
470 );
471 }
472}