//! Elliptic Curve Diffie-Hellman.
use crate::Error;
use crate::packet::Key;
use crate::Result;
use crate::constants::{
Curve,
HashAlgorithm,
SymmetricAlgorithm,
PublicKeyAlgorithm,
};
use crate::conversions::{
write_be_u64,
read_be_u64,
};
use crate::crypto::SessionKey;
use crate::crypto::mem::Protected;
use crate::crypto::mpis::{MPI, PublicKey, SecretKeyMaterial, Ciphertext};
use nettle::{cipher, curve25519, mode, Mode, ecc, ecdh, Yarrow};
/// Wraps a session key using Elliptic Curve Diffie-Hellman.
#[allow(non_snake_case)]
pub fn encrypt(recipient: &Key, session_key: &SessionKey) -> Result<Ciphertext>
{
let mut rng = Yarrow::default();
if let &PublicKey::ECDH {
ref curve, ref q,..
} = recipient.mpis() {
match curve {
Curve::Cv25519 => {
// Obtain the authenticated recipient public key R
let R = q.decode_point(curve)?.0;
// Generate an ephemeral key pair {v, V=vG}
let v: Protected =
curve25519::private_key(&mut rng).into();
// Compute the public key. We need to add an encoding
// octet in front of the key.
let mut VB = [0x40; 1 + curve25519::CURVE25519_SIZE];
curve25519::mul_g(&mut VB[1..], &v)
.expect("buffers are of the wrong size");
let VB = MPI::new(&VB);
// Compute the shared point S = vR;
let mut S: Protected =
vec![0; curve25519::CURVE25519_SIZE].into();
curve25519::mul(&mut S, &v, R)
.expect("buffers are of the wrong size");
encrypt_shared(recipient, session_key, VB, &S)
}
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => {
// Obtain the authenticated recipient public key R and
// generate an ephemeral private key v.
// Note: ecc::Point and ecc::Scalar are cleaned up by
// nettle.
let (Rx, Ry) = q.decode_point(curve)?;
let (R, v, field_sz) = match curve {
Curve::NistP256 => {
let R = ecc::Point::new::<ecc::Secp256r1>(Rx, Ry)?;
let v =
ecc::Scalar::new_random::<ecc::Secp256r1, _>(&mut rng);
let field_sz = 256;
(R, v, field_sz)
}
Curve::NistP384 => {
let R = ecc::Point::new::<ecc::Secp384r1>(Rx, Ry)?;
let v =
ecc::Scalar::new_random::<ecc::Secp384r1, _>(&mut rng);
let field_sz = 384;
(R, v, field_sz)
}
Curve::NistP521 => {
let R = ecc::Point::new::<ecc::Secp521r1>(Rx, Ry)?;
let v =
ecc::Scalar::new_random::<ecc::Secp521r1, _>(&mut rng);
let field_sz = 521;
(R, v, field_sz)
}
_ => unreachable!(),
};
// Compute the public key.
let VB = ecdh::point_mul_g(&v);
let (VBx, VBy) = VB.as_bytes();
let VB = MPI::new_weierstrass(&VBx, &VBy, field_sz);
// Compute the shared point S = vR;
let