diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-08-17 12:42:31 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-08-17 15:18:59 +0200 |
commit | 27e797638003df4a18f1e618bc88dcef753ac6cb (patch) | |
tree | 0f35f8e481cd7156539a62fd4c887b740aabd609 | |
parent | cf9fbeffb8a4be41898e4c641e7125720029718d (diff) |
openpgp: Add EC point constructors and destructor for ProtectedMPI.
- Sometimes, we store secret points, so we should provide these
convenient methods.
-rw-r--r-- | openpgp/src/crypto/mpi.rs | 90 |
1 files changed, 72 insertions, 18 deletions
diff --git a/openpgp/src/crypto/mpi.rs b/openpgp/src/crypto/mpi.rs index 61613a3c..aa5c2b4c 100644 --- a/openpgp/src/crypto/mpi.rs +++ b/openpgp/src/crypto/mpi.rs @@ -79,6 +79,11 @@ impl MPI { /// /// [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self { + Self::new_point_common(x, y, field_bits).into() + } + + /// Common implementation shared between MPI and ProtectedMPI. + fn new_point_common(x: &[u8], y: &[u8], field_bits: usize) -> Vec<u8> { let field_sz = if field_bits % 8 > 0 { 1 } else { 0 } + field_bits / 8; let mut val = vec![0x0u8; 1 + 2 * field_sz]; let x_missing = field_sz - x.len(); @@ -87,10 +92,7 @@ impl MPI { val[0] = 0x4; val[1 + x_missing..1 + field_sz].copy_from_slice(x); val[1 + field_sz + y_missing..].copy_from_slice(y); - - MPI{ - value: val.into_boxed_slice(), - } + val } /// Creates new MPI encoding a compressed EC point using native @@ -103,13 +105,15 @@ impl MPI { /// /// [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2 pub fn new_compressed_point(x: &[u8]) -> Self { + Self::new_compressed_point_common(x).into() + } + + /// Common implementation shared between MPI and ProtectedMPI. + fn new_compressed_point_common(x: &[u8]) -> Vec<u8> { let mut val = vec![0; 1 + x.len()]; val[0] = 0x40; val[1..].copy_from_slice(x); - - MPI { - value: val.into_boxed_slice(), - } + val } /// Returns the length of the MPI in bits. @@ -145,6 +149,12 @@ impl MPI { /// supported, `Error::MalformedMPI` if the point is formatted /// incorrectly. pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> { + Self::decode_point_common(self.value(), curve) + } + + /// Common implementation shared between MPI and ProtectedMPI. + fn decode_point_common<'a>(value: &'a [u8], curve: &Curve) + -> Result<(&'a [u8], &'a [u8])> { const ED25519_KEY_SIZE: usize = 32; const CURVE25519_SIZE: usize = 32; use self::Curve::*; @@ -153,21 +163,21 @@ impl MPI { assert_eq!(CURVE25519_SIZE, ED25519_KEY_SIZE); // This curve uses a custom compression format which // only contains the X coordinate. - if self.value().len() != 1 + CURVE25519_SIZE { + if value.len() != 1 + CURVE25519_SIZE { return Err(Error::MalformedMPI( format!("Bad size of Curve25519 key: {} expected: {}", - self.value().len(), + value.len(), 1 + CURVE25519_SIZE ) ).into()); } - if self.value().get(0).map(|&b| b != 0x40).unwrap_or(true) { + if value.get(0).map(|&b| b != 0x40).unwrap_or(true) { return Err(Error::MalformedMPI( "Bad encoding of Curve25519 key".into()).into()); } - Ok((&self.value()[1..], &[])) + Ok((&value[1..], &[])) }, _ => { @@ -181,20 +191,20 @@ impl MPI { + (2 // (x, y) * coordinate_length); - if self.value().len() != expected_length { + if value.len() != expected_length { return Err(Error::MalformedMPI( format!("Invalid length of MPI: {} (expected {})", - self.value().len(), expected_length)).into()); + value.len(), expected_length)).into()); } - if self.value().get(0).map(|&b| b != 0x04).unwrap_or(true) { + if value.get(0).map(|&b| b != 0x04).unwrap_or(true) { return Err(Error::MalformedMPI( format!("Bad prefix: {:?} (expected Some(0x04))", - self.value().get(0))).into()); + value.get(0))).into()); } - Ok((&self.value()[1..1 + coordinate_length], - &self.value()[1 + coordinate_length..])) + Ok((&value[1..1 + coordinate_length], + &value[1 + coordinate_length..])) }, } } @@ -340,6 +350,31 @@ impl std::hash::Hash for ProtectedMPI { } impl ProtectedMPI { + /// Creates new MPI encoding an uncompressed EC point. + /// + /// Encodes the given point on a elliptic curve (see [Section 6 of + /// RFC 6637] for details). This is used to encode public keys + /// and ciphertexts for the NIST curves (`NistP256`, `NistP384`, + /// and `NistP521`). + /// + /// [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6 + pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self { + MPI::new_point_common(x, y, field_bits).into() + } + + /// Creates new MPI encoding a compressed EC point using native + /// encoding. + /// + /// Encodes the given point on a elliptic curve (see [Section 13.2 + /// of RFC4880bis] for details). This is used to encode public + /// keys and ciphertexts for the Bernstein curves (currently + /// `X25519`). + /// + /// [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2 + pub fn new_compressed_point(x: &[u8]) -> Self { + MPI::new_compressed_point_common(x).into() + } + /// Returns the length of the MPI in bits. /// /// Leading zero-bits are not included in the returned size. @@ -357,6 +392,25 @@ impl ProtectedMPI { &self.value } + /// Decodes an EC point encoded as MPI. + /// + /// Decodes the MPI into a point on an elliptic curve (see + /// [Section 6 of RFC 6637] and [Section 13.2 of RFC4880bis] for + /// details). If the point is not compressed, the function + /// returns `(x, y)`. If it is compressed, `y` will be empty. + /// + /// [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6 + /// [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2 + /// + /// # Errors + /// + /// Returns `Error::UnsupportedEllipticCurve` if the curve is not + /// supported, `Error::MalformedMPI` if the point is formatted + /// incorrectly. + pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> { + MPI::decode_point_common(self.value(), curve) + } + /// Securely compares two MPIs in constant time. fn secure_memcmp(&self, other: &Self) -> Ordering { (self.value.len() as i32).cmp(&(other.value.len() as i32)) |