1use nettle::{
8 curve25519,
9 curve448,
10 dsa,
11 ecc,
12 ecdh,
13 ecdsa,
14 ed25519,
15 ed448,
16 rsa,
17 random::Yarrow,
18};
19
20use crate::{Error, Result};
21
22use crate::packet::{key, Key};
23use crate::crypto::asymmetric::KeyPair;
24use crate::crypto::backend::interface::Asymmetric;
25use crate::crypto::mpi::{self, MPI, ProtectedMPI, PublicKey};
26use crate::crypto::{
27 SessionKey,
28 mem::Protected,
29};
30use crate::types::{Curve, HashAlgorithm};
31
32impl Asymmetric for super::Backend {
33 fn supports_algo(algo: PublicKeyAlgorithm) -> bool {
34 use PublicKeyAlgorithm::*;
35 #[allow(deprecated)]
36 match algo {
37 X25519 | Ed25519 |
38 RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA
39 => true,
40 X448 | Ed448
41 => curve448::IS_SUPPORTED,
42 MLDSA65_Ed25519 => false,
43 MLDSA87_Ed448 => false,
44 SLHDSA128s | SLHDSA128f | SLHDSA256s => false,
45 MLKEM768_X25519 => false,
46 MLKEM1024_X448 => false,
47 ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_)
48 => false,
49 }
50 }
51
52 fn supports_curve(curve: &Curve) -> bool {
53 use Curve::*;
54 match curve {
55 NistP256 | NistP384 | NistP521 | Ed25519 | Cv25519
56 => true,
57 BrainpoolP256 | BrainpoolP384 | BrainpoolP512 | Unknown(_)
58 => false,
59 }
60 }
61
62 fn x25519_generate_key() -> Result<(Protected, [u8; 32])> {
63 debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
64 let mut rng = Yarrow::default();
65 let secret = curve25519::private_key(&mut rng);
66 let mut public = [0; 32];
67 curve25519::mul_g(&mut public, &secret)?;
68 Ok((secret.into(), public))
69 }
70
71 fn x25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
72 debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
73 let mut public = [0; 32];
74 curve25519::mul_g(&mut public, secret)?;
75 Ok(public)
76 }
77
78 fn x25519_shared_point(secret: &Protected, public: &[u8; 32])
79 -> Result<Protected> {
80 debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
81 let mut s: Protected = vec![0; 32].into();
82 curve25519::mul(&mut s, secret, public)?;
83 Ok(s)
84 }
85
86 fn x448_generate_key() -> Result<(Protected, [u8; 56])> {
87 debug_assert_eq!(curve448::CURVE448_SIZE, 56);
88 if ! curve448::IS_SUPPORTED {
89 return Err(Error::UnsupportedPublicKeyAlgorithm(
90 PublicKeyAlgorithm::Ed448).into());
91 }
92 let mut rng = Yarrow::default();
93 let secret = curve448::private_key(&mut rng);
94 let mut public = [0; 56];
95 curve448::mul_g(&mut public, &secret)?;
96 Ok((secret.into(), public))
97 }
98
99 fn x448_derive_public(secret: &Protected) -> Result<[u8; 56]> {
100 debug_assert_eq!(curve448::CURVE448_SIZE, 56);
101 if ! curve448::IS_SUPPORTED {
102 return Err(Error::UnsupportedPublicKeyAlgorithm(
103 PublicKeyAlgorithm::Ed448).into());
104 }
105 let mut public = [0; 56];
106 curve448::mul_g(&mut public, secret)?;
107 Ok(public)
108 }
109
110 fn x448_shared_point(secret: &Protected, public: &[u8; 56])
111 -> Result<Protected> {
112 debug_assert_eq!(curve448::CURVE448_SIZE, 56);
113 if ! curve448::IS_SUPPORTED {
114 return Err(Error::UnsupportedPublicKeyAlgorithm(
115 PublicKeyAlgorithm::Ed448).into());
116 }
117 let mut s: Protected = vec![0; 56].into();
118 curve448::mul(&mut s, secret, public)?;
119 Ok(s)
120 }
121
122 fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> {
123 debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
124 let mut rng = Yarrow::default();
125 let mut public = [0; 32];
126 let secret: Protected =
127 ed25519::private_key(&mut rng).into();
128 ed25519::public_key(&mut public, &secret)?;
129 Ok((secret, public))
130 }
131
132 fn ed25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
133 debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
134 let mut public = [0; 32];
135 ed25519::public_key(&mut public, secret)?;
136 Ok(public)
137 }
138
139 fn ed25519_sign(secret: &Protected, public: &[u8; 32], digest: &[u8])
140 -> Result<[u8; 64]> {
141 debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
142 debug_assert_eq!(ed25519::ED25519_SIGNATURE_SIZE, 64);
143 let mut sig = [0u8; 64];
144 ed25519::sign(public, secret, digest, &mut sig)?;
145 Ok(sig)
146 }
147
148 fn ed25519_verify(public: &[u8; 32], digest: &[u8], signature: &[u8; 64])
149 -> Result<bool> {
150 debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
151 debug_assert_eq!(ed25519::ED25519_SIGNATURE_SIZE, 64);
152 Ok(ed25519::verify(public, digest, signature)?)
153 }
154
155 fn ed448_generate_key() -> Result<(Protected, [u8; 57])> {
156 debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
157 let mut rng = Yarrow::default();
158 let mut public = [0; 57];
159 let secret: Protected =
160 ed448::private_key(&mut rng).into();
161 ed448::public_key(&mut public, &secret)?;
162 Ok((secret, public))
163 }
164
165 fn ed448_derive_public(secret: &Protected) -> Result<[u8; 57]> {
166 debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
167 let mut public = [0; 57];
168 ed448::public_key(&mut public, secret)?;
169 Ok(public)
170 }
171
172 fn ed448_sign(secret: &Protected, public: &[u8; 57], digest: &[u8])
173 -> Result<[u8; 114]> {
174 debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
175 debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114);
176 let mut sig = [0u8; 114];
177 ed448::sign(public, secret, digest, &mut sig)?;
178 Ok(sig)
179 }
180
181 fn ed448_verify(public: &[u8; 57], digest: &[u8], signature: &[u8; 114])
182 -> Result<bool> {
183 debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
184 debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114);
185 Ok(ed448::verify(public, digest, signature)?)
186 }
187
188 fn dsa_generate_key(p_bits: usize)
189 -> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>
190 {
191 let mut rng = Yarrow::default();
192 let q_bits = if p_bits <= 1024 { 160 } else { 256 };
193 let params = dsa::Params::generate(&mut rng, p_bits, q_bits)?;
194 let (p, q) = params.primes();
195 let g = params.g();
196 let (y, x) = dsa::generate_keypair(¶ms, &mut rng);
197 Ok((p.into(), q.into(), g.into(), y.as_bytes().into(),
198 x.as_bytes().into()))
199 }
200
201 fn dsa_sign(x: &ProtectedMPI,
202 p: &MPI, q: &MPI, g: &MPI, _y: &MPI,
203 digest: &[u8])
204 -> Result<(MPI, MPI)>
205 {
206 let mut rng = Yarrow::default();
207 let params = dsa::Params::new(p.value(), q.value(), g.value());
208 let secret = dsa::PrivateKey::new(x.value());
209
210 let sig = dsa::sign(¶ms, &secret, digest, &mut rng)?;
211
212 Ok((MPI::new(&sig.r()), MPI::new(&sig.s())))
213 }
214
215 fn dsa_verify(p: &MPI, q: &MPI, g: &MPI, y: &MPI,
216 digest: &[u8],
217 r: &MPI, s: &MPI)
218 -> Result<bool>
219 {
220 let key = dsa::PublicKey::new(y.value());
221 let params = dsa::Params::new(p.value(), q.value(), g.value());
222 let signature = dsa::Signature::new(r.value(), s.value());
223 Ok(dsa::verify(¶ms, &key, digest, &signature))
224 }
225}
226
227impl KeyPair {
228 pub(crate) fn sign_backend(&self,
229 secret: &mpi::SecretKeyMaterial,
230 hash_algo: HashAlgorithm,
231 digest: &[u8])
232 -> Result<mpi::Signature>
233 {
234 use crate::PublicKeyAlgorithm::*;
235
236 let mut rng = Yarrow::default();
237
238 #[allow(deprecated)]
239 match (self.public().pk_algo(), self.public().mpis(), secret)
240 {
241 (RSASign,
242 &PublicKey::RSA { ref e, ref n },
243 &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) |
244 (RSAEncryptSign,
245 &PublicKey::RSA { ref e, ref n },
246 &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) => {
247 let public = rsa::PublicKey::new(n.value(), e.value())?;
248 let secret = rsa::PrivateKey::new(d.value(), p.value(),
249 q.value(), Option::None)?;
250
251 let mut sig = vec![0u8; n.value().len()];
253
254 rsa::sign_digest_pkcs1(&public, &secret, digest,
261 hash_algo.oid()?,
262 &mut rng, &mut sig)?;
263
264 Ok(mpi::Signature::RSA {
265 s: MPI::new(&sig),
266 })
267 },
268
269 (ECDSA,
270 &PublicKey::ECDSA { ref curve, .. },
271 &mpi::SecretKeyMaterial::ECDSA { ref scalar }) => {
272 let secret = match curve {
273 Curve::NistP256 =>
274 ecc::Scalar::new::<ecc::Secp256r1>(
275 scalar.value())?,
276 Curve::NistP384 =>
277 ecc::Scalar::new::<ecc::Secp384r1>(
278 scalar.value())?,
279 Curve::NistP521 =>
280 ecc::Scalar::new::<ecc::Secp521r1>(
281 scalar.value())?,
282 _ =>
283 return Err(
284 Error::UnsupportedEllipticCurve(curve.clone())
285 .into()),
286 };
287
288 let sig = ecdsa::sign(&secret, digest, &mut rng);
289
290 Ok(mpi::Signature::ECDSA {
291 r: MPI::new(&sig.r()),
292 s: MPI::new(&sig.s()),
293 })
294 },
295
296 (pk_algo, _, _) => Err(Error::InvalidOperation(format!(
297 "unsupported combination of algorithm {:?}, key {:?}, \
298 and secret key {:?}",
299 pk_algo, self.public(), self.secret())).into()),
300 }
301 }
302}
303
304impl KeyPair {
305 pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext,
306 plaintext_len: Option<usize>)
307 -> Result<SessionKey>
308 {
309 use crate::PublicKeyAlgorithm::*;
310
311 Ok(match (self.public().mpis(), secret, ciphertext) {
312 (PublicKey::RSA{ ref e, ref n },
313 mpi::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. },
314 mpi::Ciphertext::RSA{ ref c }) => {
315 let public = rsa::PublicKey::new(n.value(), e.value())?;
316 let secret = rsa::PrivateKey::new(d.value(), p.value(),
317 q.value(), Option::None)?;
318 let mut rand = Yarrow::default();
319 if let Some(l) = plaintext_len {
320 let mut plaintext: SessionKey = vec![0; l].into();
321 rsa::decrypt_pkcs1(&public, &secret, &mut rand,
322 c.value(), plaintext.as_mut())?;
323 plaintext
324 } else {
325 rsa::decrypt_pkcs1_insecure(&public, &secret,
326 &mut rand, c.value())?
327 .into()
328 }
329 }
330
331 (PublicKey::ElGamal{ .. },
332 mpi::SecretKeyMaterial::ElGamal{ .. },
333 mpi::Ciphertext::ElGamal{ .. }) => {
334 #[allow(deprecated)]
335 return Err(
336 Error::UnsupportedPublicKeyAlgorithm(ElGamalEncrypt).into());
337 },
338
339 (PublicKey::ECDH{ .. },
340 mpi::SecretKeyMaterial::ECDH { .. },
341 mpi::Ciphertext::ECDH { .. }) =>
342 crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
343 plaintext_len)?,
344
345 (public, secret, ciphertext) =>
346 return Err(Error::InvalidOperation(format!(
347 "unsupported combination of key pair {:?}/{:?} \
348 and ciphertext {:?}",
349 public, secret, ciphertext)).into()),
350 })
351 }
352}
353
354
355impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
356 pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result<mpi::Ciphertext> {
358 use crate::PublicKeyAlgorithm::*;
359
360 #[allow(deprecated)]
361 match self.pk_algo() {
362 RSAEncryptSign | RSAEncrypt => {
363 match self.mpis() {
365 mpi::PublicKey::RSA { e, n } => {
366 let ciphertext_len = n.value().len();
368 if data.len() + 11 > ciphertext_len {
369 return Err(Error::InvalidArgument(
370 "Plaintext data too large".into()).into());
371 }
372
373 let mut esk = vec![0u8; ciphertext_len];
374 let mut rng = Yarrow::default();
375 let pk = rsa::PublicKey::new(n.value(), e.value())?;
376 rsa::encrypt_pkcs1(&pk, &mut rng, data,
377 &mut esk)?;
378 Ok(mpi::Ciphertext::RSA {
379 c: MPI::new(&esk),
380 })
381 },
382 pk => {
383 Err(Error::MalformedPacket(
384 format!(
385 "Key: Expected RSA public key, got {:?}",
386 pk)).into())
387 },
388 }
389 },
390
391 ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(),
392 data),
393
394 RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448
395 | MLDSA65_Ed25519 | MLDSA87_Ed448
396 | SLHDSA128s | SLHDSA128f | SLHDSA256s =>
397 Err(Error::InvalidOperation(
398 format!("{} is not an encryption algorithm", self.pk_algo())
399 ).into()),
400
401 X25519 | X448 | ElGamalEncrypt | ElGamalEncryptSign |
404 MLKEM768_X25519 | MLKEM1024_X448 | Private(_) | Unknown(_) =>
407 Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()),
408 }
409 }
410
411 pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm,
413 digest: &[u8]) -> Result<()>
414 {
415 use crate::crypto::mpi::Signature;
416
417 let ok = match (self.mpis(), sig) {
418 (PublicKey::RSA { e, n }, Signature::RSA { s }) => {
419 let key = rsa::PublicKey::new(n.value(), e.value())?;
420
421 rsa::verify_digest_pkcs1(&key, digest, hash_algo.oid()?,
428 s.value())?
429 },
430 (PublicKey::ECDSA { curve, q }, Signature::ECDSA { s, r }) =>
431 {
432 let (x, y) = q.decode_point(curve)?;
433 let key = match curve {
434 Curve::NistP256 => ecc::Point::new::<ecc::Secp256r1>(x, y)?,
435 Curve::NistP384 => ecc::Point::new::<ecc::Secp384r1>(x, y)?,
436 Curve::NistP521 => ecc::Point::new::<ecc::Secp521r1>(x, y)?,
437 _ => return Err(
438 Error::UnsupportedEllipticCurve(curve.clone()).into()),
439 };
440
441 let signature = dsa::Signature::new(r.value(), s.value());
442 ecdsa::verify(&key, digest, &signature)
443 },
444 _ => return Err(Error::MalformedPacket(format!(
445 "unsupported combination of key {} and signature {:?}.",
446 self.pk_algo(), sig)).into()),
447 };
448
449 if ok {
450 Ok(())
451 } else {
452 Err(Error::ManipulatedMessage.into())
453 }
454 }
455}
456
457use std::time::SystemTime;
458use crate::packet::key::{Key4, SecretParts};
459use crate::types::PublicKeyAlgorithm;
460
461impl<R> Key4<SecretParts, R>
462 where R: key::KeyRole,
463{
464 pub fn import_secret_rsa<T>(d: &[u8], p: &[u8], q: &[u8], ctime: T)
470 -> Result<Self> where T: Into<Option<SystemTime>>
471 {
472 let sec = rsa::PrivateKey::new(d, p, q, None)?;
473 let key = sec.public_key()?;
474 let (a, b, c) = sec.as_rfc4880();
475
476 Self::with_secret(
477 ctime.into().unwrap_or_else(crate::now),
478 PublicKeyAlgorithm::RSAEncryptSign,
479 mpi::PublicKey::RSA {
480 e: mpi::MPI::new(&key.e()[..]),
481 n: mpi::MPI::new(&key.n()[..]),
482 },
483 mpi::SecretKeyMaterial::RSA {
484 d: d.into(),
485 p: a.into(),
486 q: b.into(),
487 u: c.into(),
488 }.into())
489 }
490
491 pub fn generate_rsa(bits: usize) -> Result<Self> {
493 let mut rng = Yarrow::default();
494
495 let (public, private) = rsa::generate_keypair(&mut rng, bits as u32)?;
496 let (p, q, u) = private.as_rfc4880();
497 let public_mpis = PublicKey::RSA {
498 e: MPI::new(&*public.e()),
499 n: MPI::new(&*public.n()),
500 };
501 let private_mpis = mpi::SecretKeyMaterial::RSA {
502 d: private.d().into(),
503 p: p.into(),
504 q: q.into(),
505 u: u.into(),
506 };
507
508 Self::with_secret(
509 crate::now(),
510 PublicKeyAlgorithm::RSAEncryptSign,
511 public_mpis,
512 private_mpis.into())
513 }
514
515 pub(crate) fn generate_ecc_backend(for_signing: bool, curve: Curve)
522 -> Result<(PublicKeyAlgorithm,
523 mpi::PublicKey,
524 mpi::SecretKeyMaterial)>
525 {
526 let mut rng = Yarrow::default();
527
528 match (curve.clone(), for_signing) {
529 (Curve::Ed25519, true) =>
530 unreachable!("handled in Key4::generate_ecc"),
531
532 (Curve::Cv25519, false) =>
533 unreachable!("handled in Key4::generate_ecc"),
534
535 (Curve::NistP256, true) | (Curve::NistP384, true)
536 | (Curve::NistP521, true) => {
537 let (public, private, field_sz) = match curve {
538 Curve::NistP256 => {
539 let (pu, sec) =
540 ecdsa::generate_keypair::<ecc::Secp256r1, _>(&mut rng)?;
541 (pu, sec, 256)
542 }
543 Curve::NistP384 => {
544 let (pu, sec) =
545 ecdsa::generate_keypair::<ecc::Secp384r1, _>(&mut rng)?;
546 (pu, sec, 384)
547 }
548 Curve::NistP521 => {
549 let (pu, sec) =
550 ecdsa::generate_keypair::<ecc::Secp521r1, _>(&mut rng)?;
551 (pu, sec, 521)
552 }
553 _ => unreachable!(),
554 };
555 let (pub_x, pub_y) = public.as_bytes();
556 let public_mpis = mpi::PublicKey::ECDSA{
557 curve,
558 q: MPI::new_point(&pub_x, &pub_y, field_sz),
559 };
560 let private_mpis = mpi::SecretKeyMaterial::ECDSA{
561 scalar: private.as_bytes().into(),
562 };
563
564 Ok((PublicKeyAlgorithm::ECDSA, public_mpis, private_mpis))
565 }
566
567 (Curve::NistP256, false) | (Curve::NistP384, false)
568 | (Curve::NistP521, false) => {
569 let (private, field_sz) = match curve {
570 Curve::NistP256 => {
571 let pv =
572 ecc::Scalar::new_random::<ecc::Secp256r1, _>(&mut rng);
573
574 (pv, 256)
575 }
576 Curve::NistP384 => {
577 let pv =
578 ecc::Scalar::new_random::<ecc::Secp384r1, _>(&mut rng);
579
580 (pv, 384)
581 }
582 Curve::NistP521 => {
583 let pv =
584 ecc::Scalar::new_random::<ecc::Secp521r1, _>(&mut rng);
585
586 (pv, 521)
587 }
588 _ => unreachable!(),
589 };
590 let public = ecdh::point_mul_g(&private);
591 let (pub_x, pub_y) = public.as_bytes();
592 let public_mpis = mpi::PublicKey::ECDH{
593 q: MPI::new_point(&pub_x, &pub_y, field_sz),
594 hash:
595 crate::crypto::ecdh::default_ecdh_kdf_hash(&curve),
596 sym:
597 crate::crypto::ecdh::default_ecdh_kek_cipher(&curve),
598 curve,
599 };
600 let private_mpis = mpi::SecretKeyMaterial::ECDH{
601 scalar: private.as_bytes().into(),
602 };
603
604 Ok((PublicKeyAlgorithm::ECDH, public_mpis, private_mpis))
605 }
606
607 _ => Err(Error::UnsupportedEllipticCurve(curve).into()),
608 }
609 }
610}