1use ecdsa::SigningKey;
2use elliptic_curve::sec1::ToEncodedPoint;
3use p521::NistP521;
4use rand::{CryptoRng, Rng};
5use signature::hazmat::{PrehashSigner, PrehashVerifier};
6use zeroize::ZeroizeOnDrop;
7
8use crate::crypto::ecc_curve::ECCCurve;
9use crate::crypto::hash::HashAlgorithm;
10use crate::crypto::Signer;
11use crate::errors::Result;
12use crate::types::EcdsaPublicParams;
13use crate::types::{Mpi, PlainSecretParams, PublicParams};
14
15#[derive(Clone, PartialEq, Eq, ZeroizeOnDrop, derive_more::Debug)]
16pub enum SecretKey {
17 P256(#[debug("..")] p256::SecretKey),
18 P384(#[debug("..")] p384::SecretKey),
19 P521(#[debug("..")] p521::SecretKey),
20 Secp256k1(#[debug("..")] k256::SecretKey),
21 Unsupported {
22 #[debug("..")]
24 x: Mpi,
25 #[zeroize(skip)]
26 curve: ECCCurve,
27 },
28}
29
30impl Signer for SecretKey {
31 fn sign(
32 &self,
33 hash: HashAlgorithm,
34 digest: &[u8],
35 pub_params: &PublicParams,
36 ) -> Result<Vec<Vec<u8>>> {
37 ensure!(
38 matches!(pub_params, PublicParams::ECDSA(..)),
39 "invalid public params"
40 );
41
42 if let Some(field_size) = self.secret_key_length() {
43 let field_size = match field_size {
47 66 => 64, s => s,
49 };
50
51 ensure!(
52 digest.len() >= field_size,
53 "Hash digest size ({:?}) must at least match key size ({:?})",
54 hash,
55 self
56 );
57 }
58
59 let (r, s) = match self {
60 Self::P256(secret_key) => {
61 let secret = p256::ecdsa::SigningKey::from(secret_key);
62 let signature: p256::ecdsa::Signature = secret.sign_prehash(digest)?;
63 let (r, s) = signature.split_bytes();
64 (r.to_vec(), s.to_vec())
65 }
66 Self::P384(secret_key) => {
67 let secret = p384::ecdsa::SigningKey::from(secret_key);
68 let signature: p384::ecdsa::Signature = secret.sign_prehash(digest)?;
69 let (r, s) = signature.split_bytes();
70 (r.to_vec(), s.to_vec())
71 }
72 Self::P521(secret_key) => {
73 let secret: SigningKey<NistP521> = secret_key.into();
74 let signing_key = p521::ecdsa::SigningKey::from(secret);
75 let signature: p521::ecdsa::Signature = signing_key.sign_prehash(digest)?;
76 let (r, s) = signature.split_bytes();
77 (r.to_vec(), s.to_vec())
78 }
79 Self::Secp256k1(secret_key) => {
80 let secret = k256::ecdsa::SigningKey::from(secret_key);
81 let signature: k256::ecdsa::Signature = secret.sign_prehash(digest)?;
82 let (r, s) = signature.split_bytes();
83 (r.to_vec(), s.to_vec())
84 }
85 Self::Unsupported { curve, .. } => {
86 unsupported_err!("curve {:?} for ECDSA", curve)
87 }
88 };
89
90 Ok(vec![r, s])
91 }
92}
93
94impl SecretKey {
95 pub(crate) fn secret_key_length(&self) -> Option<usize> {
96 match self {
97 Self::P256 { .. } => Some(32),
98 Self::P384 { .. } => Some(48),
99 Self::P521 { .. } => Some(66),
100 Self::Secp256k1 { .. } => Some(32),
101 Self::Unsupported { .. } => None,
102 }
103 }
104}
105pub fn generate_key<R: Rng + CryptoRng>(
107 mut rng: R,
108 curve: &ECCCurve,
109) -> Result<(PublicParams, PlainSecretParams)> {
110 match curve {
111 ECCCurve::P256 => {
112 let secret = p256::SecretKey::random(&mut rng);
113 let public = secret.public_key();
114 let secret = Mpi::from_slice(secret.to_bytes().as_slice());
115
116 Ok((
117 PublicParams::ECDSA(EcdsaPublicParams::P256 {
118 key: public,
119 p: Mpi::from_slice(public.to_encoded_point(false).as_bytes()),
120 }),
121 PlainSecretParams::ECDSA(secret),
122 ))
123 }
124
125 ECCCurve::P384 => {
126 let secret = p384::SecretKey::random(&mut rng);
127 let public = secret.public_key();
128 let secret = Mpi::from_slice(secret.to_bytes().as_slice());
129
130 Ok((
131 PublicParams::ECDSA(EcdsaPublicParams::P384 {
132 key: public,
133 p: Mpi::from_slice(public.to_encoded_point(false).as_bytes()),
134 }),
135 PlainSecretParams::ECDSA(secret),
136 ))
137 }
138
139 ECCCurve::P521 => {
140 let secret = p521::SecretKey::random(&mut rng);
141 let public = secret.public_key();
142 let secret = Mpi::from_slice(secret.to_bytes().as_slice());
143
144 Ok((
145 PublicParams::ECDSA(EcdsaPublicParams::P521 {
146 key: public,
147 p: Mpi::from_slice(public.to_encoded_point(false).as_bytes()),
148 }),
149 PlainSecretParams::ECDSA(secret),
150 ))
151 }
152
153 ECCCurve::Secp256k1 => {
154 let secret = k256::SecretKey::random(&mut rng);
155 let public = secret.public_key();
156 let secret = Mpi::from_slice(secret.to_bytes().as_slice());
157
158 Ok((
159 PublicParams::ECDSA(EcdsaPublicParams::Secp256k1 {
160 key: public,
161 p: Mpi::from_slice(public.to_encoded_point(false).as_bytes()),
162 }),
163 PlainSecretParams::ECDSA(secret),
164 ))
165 }
166
167 _ => unsupported_err!("curve {:?} for ECDSA", curve),
168 }
169}
170
171pub fn verify(
173 p: &EcdsaPublicParams,
174 hash: HashAlgorithm,
175 hashed: &[u8],
176 sig: &[Mpi],
177) -> Result<()> {
178 if let Some(field_size) = p.secret_key_length() {
180 ensure!(
182 hashed.len() >= field_size / 2,
183 "Hash algorithm {:?} cannot be combined with key {:?}",
184 hash,
185 p
186 );
187
188 let min_hash_len = match field_size {
192 521 => 512,
194
195 f => f,
196 };
197 let Some(digest_size) = hash.digest_size() else {
198 bail!("ECDSA signature: invalid hash algorithm: {:?}", hash);
199 };
200 ensure!(
201 digest_size * 8 >= min_hash_len,
202 "ECDSA signature: hash algorithm {:?} is too weak for key {:?}",
203 hash,
204 p
205 );
206 }
207
208 match p {
209 EcdsaPublicParams::P256 { key, .. } => {
210 const FLEN: usize = 32;
211 ensure_eq!(sig.len(), 2);
212 let r = sig[0].as_bytes();
213 let s = sig[1].as_bytes();
214 ensure!(r.len() <= FLEN, "invalid R (len)");
215 ensure!(s.len() <= FLEN, "invalid S (len)");
216 let mut sig_bytes = [0u8; 2 * FLEN];
217
218 sig_bytes[(FLEN - r.len())..FLEN].copy_from_slice(r);
220 sig_bytes[FLEN + (FLEN - s.len())..].copy_from_slice(s);
221
222 let sig = p256::ecdsa::Signature::try_from(&sig_bytes[..])?;
223 let pk = p256::ecdsa::VerifyingKey::from_affine(key.as_affine().to_owned())?;
224
225 pk.verify_prehash(hashed, &sig)?;
226
227 Ok(())
228 }
229 EcdsaPublicParams::P384 { key, .. } => {
230 const FLEN: usize = 48;
231 ensure_eq!(sig.len(), 2);
232
233 let r = sig[0].as_bytes();
234 let s = sig[1].as_bytes();
235
236 ensure!(r.len() <= FLEN, "invalid R (len)");
237 ensure!(s.len() <= FLEN, "invalid S (len)");
238
239 let mut sig_bytes = [0u8; 2 * FLEN];
240
241 sig_bytes[(FLEN - r.len())..FLEN].copy_from_slice(r);
243 sig_bytes[FLEN + (FLEN - s.len())..].copy_from_slice(s);
244
245 let pk = p384::ecdsa::VerifyingKey::from_affine(key.as_affine().to_owned())?;
246 let sig = p384::ecdsa::Signature::try_from(&sig_bytes[..])?;
247
248 pk.verify_prehash(hashed, &sig)?;
249
250 Ok(())
251 }
252 EcdsaPublicParams::P521 { key, .. } => {
253 const FLEN: usize = 66;
254 ensure_eq!(sig.len(), 2);
255
256 let r = sig[0].as_bytes();
257 let s = sig[1].as_bytes();
258
259 ensure!(r.len() <= FLEN, "invalid R (len)");
260 ensure!(s.len() <= FLEN, "invalid S (len)");
261
262 let mut sig_bytes = [0u8; 2 * FLEN];
263
264 sig_bytes[(FLEN - r.len())..FLEN].copy_from_slice(r);
266 sig_bytes[FLEN + (FLEN - s.len())..].copy_from_slice(s);
267
268 let pk = p521::ecdsa::VerifyingKey::from_affine(key.as_affine().to_owned())?;
269 let sig = p521::ecdsa::Signature::try_from(&sig_bytes[..])?;
270
271 pk.verify_prehash(hashed, &sig)?;
272
273 Ok(())
274 }
275 EcdsaPublicParams::Secp256k1 { key, .. } => {
276 const FLEN: usize = 32;
277 ensure_eq!(sig.len(), 2);
278 let r = sig[0].as_bytes();
279 let s = sig[1].as_bytes();
280 ensure!(r.len() <= FLEN, "invalid R (len)");
281 ensure!(s.len() <= FLEN, "invalid S (len)");
282 let mut sig_bytes = [0u8; 2 * FLEN];
283
284 sig_bytes[(FLEN - r.len())..FLEN].copy_from_slice(r);
286 sig_bytes[FLEN + (FLEN - s.len())..].copy_from_slice(s);
287
288 let pk = k256::ecdsa::VerifyingKey::from_affine(key.as_affine().to_owned())?;
289 let sig = k256::ecdsa::Signature::try_from(&sig_bytes[..])?;
290
291 pk.verify_prehash(hashed, &sig)?;
292
293 Ok(())
294 }
295 EcdsaPublicParams::Unsupported { curve, .. } => {
296 unsupported_err!("curve {:?} for ECDSA", curve.to_string())
297 }
298 }
299}