1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
//! Elliptic Curve Diffie-Hellman.
use botan::{
RandomNumberGenerator,
Privkey,
};
use crate::{
Error,
Result,
};
use crate::crypto::SessionKey;
use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap2};
use crate::crypto::mem::Protected;
use crate::crypto::mpi::{
MPI,
PublicKey, SecretKeyMaterial, Ciphertext};
use crate::packet::{key, Key};
use crate::types::Curve;
/// Wraps a session key using Elliptic Curve Diffie-Hellman.
#[allow(non_snake_case)]
pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
session_key: &SessionKey)
-> Result<Ciphertext>
where R: key::KeyRole
{
let mut rng = RandomNumberGenerator::new_userspace()?;
if let PublicKey::ECDH {
ref curve, ref q,..
} = recipient.mpis() {
match curve {
Curve::Cv25519 =>
Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
// N/A
Curve::Unknown(_) if ! curve.is_brainpoolp384() =>
Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
Curve::Ed25519 =>
Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 |
Curve::BrainpoolP256 |
Curve::Unknown(_) | // XXX: this is BrainpoolP384
Curve::BrainpoolP512 => {
// Obtain the recipient public key R
let R = &q.value();
// Generate an ephemeral key pair {v, V=vG}
let field_size = curve.field_size()?;
let v = Privkey::create("ECDH", curve.botan_name()?, &mut rng)?;
let Vx = v.pubkey()?.get_field("public_x")?;
let Vy = v.pubkey()?.get_field("public_y")?;
// Compute the shared point S = vR;
let S: Protected = v.agree(&R, 32, b"", "Raw")?.into();
let Sx: Protected = S[..field_size].into();
encrypt_wrap(recipient, session_key,
MPI::new_point(&Vx.to_bin()?, &Vy.to_bin()?,
field_size * 8),
&Sx.into())
}
}
} else {
Err(Error::InvalidArgument("Expected an ECDHPublicKey".into()).into())
}
}
/// Unwraps a session key using Elliptic Curve Diffie-Hellman.
#[allow(non_snake_case)]
pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
ciphertext: &Ciphertext,
plaintext_len: Option<usize>)
-> Result<SessionKey>
where R: key::KeyRole
{
match (recipient.mpis(), recipient_sec, ciphertext) {
(PublicKey::ECDH { ref curve, ..},
SecretKeyMaterial::ECDH { ref scalar, },
Ciphertext::ECDH { ref e, .. }) =>
{
let S: Protected = match curve {
Curve::Cv25519 => return
Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
// N/A
Curve::Unknown(_) if ! curve.is_brainpoolp384() => return
Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
Curve::Ed25519 => return
Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 |
Curve::BrainpoolP256 |
Curve::Unknown(_) | // XXX: this is BrainpoolP384
Curve::BrainpoolP512 => {
// Get the public part V of the ephemeral key.
let V = &e.value();
// Get our secret key.
let r = Privkey::load_ecdh(
&botan::MPI::new_from_bytes(scalar.value())?,
curve.botan_name()?)?;
// Compute the shared point S = rV = rvG, where (r, R)
// is the recipient's key pair.
r.agree(V, curve.field_size()?, b"", "Raw")?.into()
},
};
decrypt_unwrap2(recipient.role_as_unspecified(), &S, ciphertext,
plaintext_len)
}
_ =>
Err(Error::InvalidArgument("Expected an ECDHPublicKey".into()).into()),
}
}
|