Project import generated by Copybara.
GitOrigin-RevId: 06b0c815d958bef0a60978d0766d65af839e37b6
Change-Id: Ifac0c45ae509ca8a8ed793fac5c981d4e23d3bf9
diff --git a/nearby/crypto/crypto_provider/Cargo.toml b/nearby/crypto/crypto_provider/Cargo.toml
index 60f8626..e7dd8ba 100644
--- a/nearby/crypto/crypto_provider/Cargo.toml
+++ b/nearby/crypto/crypto_provider/Cargo.toml
@@ -4,11 +4,14 @@
edition.workspace = true
publish.workspace = true
+[dependencies]
+tinyvec.workspace = true
+
[dev-dependencies]
criterion.workspace = true
hex-literal.workspace = true
crypto_provider_openssl.workspace = true
-crypto_provider_rustcrypto.workspace = true
+crypto_provider_rustcrypto = { workspace = true, features = ["std"] }
rand_ext.workspace = true
rand.workspace = true
@@ -17,6 +20,7 @@
std = []
alloc = []
test_vectors = []
+raw_private_key_permit = []
[[bench]]
name = "hmac_bench"
diff --git a/nearby/crypto/crypto_provider/src/aead.rs b/nearby/crypto/crypto_provider/src/aead.rs
new file mode 100644
index 0000000..165272e
--- /dev/null
+++ b/nearby/crypto/crypto_provider/src/aead.rs
@@ -0,0 +1,86 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+
+/// An implementation of AES-GCM-SIV.
+///
+/// An AesGcmSiv impl may be used for encryption and decryption.
+pub trait AesGcmSiv: Aead<Nonce = [u8; 12]> {}
+
+/// An implementation of AES-GCM.
+///
+/// An AesGcm impl may be used for encryption and decryption.
+pub trait AesGcm: Aead<Nonce = [u8; 12]> {}
+
+/// Error returned on unsuccessful AEAD operation.
+#[derive(Debug)]
+pub struct AeadError;
+
+/// Initializes an AEAD
+pub trait AeadInit<K: crate::aes::AesKey> {
+ /// Instantiates a new instance of the AEAD from key material.
+ fn new(key: &K) -> Self;
+}
+
+/// Authenticated Encryption with Associated Data (AEAD) algorithm, where `N` is the size of the
+/// Nonce. Encrypts and decrypts buffers in-place.
+pub trait Aead {
+ /// The size of the authentication tag, this is appended to the message on the encrypt operation
+ /// and truncated from the plaintext after decrypting.
+ const TAG_SIZE: usize;
+
+ /// The cryptographic nonce used by the AEAD. The nonce must be unique for all messages with
+ /// the same key. This is critically important - nonce reuse may completely undermine the
+ /// security of the AEAD. Nonces may be predictable and public, so long as they are unique.
+ type Nonce: AsRef<[u8]>;
+
+ /// The type of the tag, which should always be [u8; Self::TAG_SIZE].
+ type Tag: AsRef<[u8]>;
+
+ /// Encrypt the given buffer containing a plaintext message. On success returns the encrypted
+ /// `msg` and appended auth tag, which will result in a Vec which is `Self::TAG_SIZE` bytes
+ /// greater than the initial message.
+ #[cfg(feature = "alloc")]
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
+
+ /// Encrypt the given buffer containing a plaintext message in-place, and returns the tag in the
+ /// result value.
+ fn encrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError>;
+
+ /// Decrypt the message, returning the decrypted plaintext or an error in the event the
+ /// provided authentication tag does not match the given ciphertext. On success the returned
+ /// Vec will only contain the plaintext and so will be `Self::TAG_SIZE` bytes less than the
+ /// initial message.
+ #[cfg(feature = "alloc")]
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
+
+ /// Decrypt the message in-place, returning an error and leaving the input `msg` unchanged in
+ /// the event the provided authentication tag does not match the given ciphertext.
+ fn decrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ tag: &Self::Tag,
+ ) -> Result<(), AeadError>;
+}
diff --git a/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs
deleted file mode 100644
index 3be7db3..0000000
--- a/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Traits for AES-GCM-SIV.
-
-extern crate alloc;
-use crate::aead::Aead;
-
-/// An implementation of AES-GCM-SIV.
-///
-/// An AesGcmSiv impl may be used for encryption and decryption.
-pub trait AesGcmSiv: Aead<Nonce = [u8; 12]> {}
diff --git a/nearby/crypto/crypto_provider/src/aead/mod.rs b/nearby/crypto/crypto_provider/src/aead/mod.rs
deleted file mode 100644
index 27284a9..0000000
--- a/nearby/crypto/crypto_provider/src/aead/mod.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-extern crate alloc;
-use alloc::vec::Vec;
-
-/// Contains traits for the AES-GCM-SIV AEAD algorithm.
-pub mod aes_gcm_siv;
-
-/// Error returned on unsuccessful AEAD operation.
-pub struct AeadError;
-
-/// Authenticated Encryption with Associated Data (AEAD) algorithm, where `N` is the size of the
-/// Nonce. Encrypts and decrypts buffers in-place.
-pub trait Aead {
- /// The size of the authentication tag, this is appended to the message on the encrypt operation
- /// and truncated from the plaintext after decrypting.
- const TAG_SIZE: usize;
-
- /// The cryptographic nonce used by the AEAD. The nonce must be unique for all messages with
- /// the same key. This is critically important - nonce reuse may completely undermine the
- /// security of the AEAD. Nonces may be predictable and public, so long as they are unique.
- type Nonce;
-
- /// The key material used to initialize the AEAD.
- type Key;
-
- /// Instantiates a new instance of the AEAD from key material.
- fn new(key: &Self::Key) -> Self;
-
- /// Encrypt the given buffer containing a plaintext message in-place. On success increases the
- /// buffer by `Self::TAG_SIZE` bytes and appends the auth tag to the end of `msg`.
- fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &Self::Nonce) -> Result<(), AeadError>;
-
- /// Decrypt the message in-place, returning an error in the event the provided authentication
- /// tag does not match the given ciphertext. The buffer will be truncated to the length of the
- /// original plaintext message upon success.
- fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &Self::Nonce) -> Result<(), AeadError>;
-}
diff --git a/nearby/crypto/crypto_provider/src/aes/cbc.rs b/nearby/crypto/crypto_provider/src/aes/cbc.rs
index e32c588..59ce52d 100644
--- a/nearby/crypto/crypto_provider/src/aes/cbc.rs
+++ b/nearby/crypto/crypto_provider/src/aes/cbc.rs
@@ -14,7 +14,10 @@
//! Traits for AES-CBC 256 with PKCS7 padding.
+#[cfg(feature = "alloc")]
extern crate alloc;
+use crate::tinyvec::SliceVec;
+#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use super::Aes256Key;
@@ -24,15 +27,53 @@
/// Trait for implementing AES-CBC with PKCS7 padding.
pub trait AesCbcPkcs7Padded {
+ /// Calculate the padded output length (e.g. output of `encrypt`) from the unpadded length (e.g.
+ /// input message of `encrypt`).
+ fn padded_output_len(unpadded_len: usize) -> usize {
+ (unpadded_len - (unpadded_len % 16))
+ .checked_add(16)
+ .expect("Padded output length is larger than usize::MAX")
+ }
+
/// Encrypt message using `key` and `iv`, returning a ciphertext.
+ #[cfg(feature = "alloc")]
fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8>;
+
+ /// Encrypt message using `key` and `iv` in-place in the given `message` vec. The given slice
+ /// vec should have enough capacity to contain both the ciphertext and the padding (which can be
+ /// calculated from `padded_output_len()`). If it doesn't have enough capacity, an error will be
+ /// returned. The contents of the input `message` buffer is undefined in that case.
+ fn encrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError>;
+
/// Decrypt ciphertext using `key` and `iv`, returning the original message if `Ok()` otherwise
/// a `DecryptionError` indicating the type of error that occurred while decrypting.
+ #[cfg(feature = "alloc")]
fn decrypt(
key: &Aes256Key,
iv: &AesCbcIv,
ciphertext: &[u8],
) -> Result<Vec<u8>, DecryptionError>;
+
+ /// Decrypt ciphertext using `key` and `iv` and unpad it in-place. Returning the original
+ /// message if `Ok()` otherwise a `DecryptionError` indicating the type of error that occurred
+ /// while decrypting. In that case, the contents of the `ciphertext` buffer is undefined.
+ fn decrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError>;
+}
+
+/// Error type for describing what went wrong encrypting a message.
+#[derive(Debug, PartialEq, Eq)]
+pub enum EncryptionError {
+ /// Failed to add PKCS7 padding to the output when encrypting a message. This typically happens
+ /// when the given output buffer does not have enough capacity to append the padding.
+ PaddingFailed,
}
/// Error type for describing what went wrong decrypting a ciphertext.
@@ -43,3 +84,65 @@
/// correctly. Exposing padding errors can cause a padding oracle vulnerability.
BadPadding,
}
+
+#[cfg(test)]
+mod test {
+ #[cfg(feature = "alloc")]
+ extern crate alloc;
+ #[cfg(feature = "alloc")]
+ use alloc::vec::Vec;
+
+ use crate::aes::Aes256Key;
+ use crate::tinyvec::SliceVec;
+
+ use super::{AesCbcIv, AesCbcPkcs7Padded, DecryptionError, EncryptionError};
+
+ #[test]
+ fn test_padded_output_len() {
+ assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(0), 16);
+ assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(15), 16);
+ assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(16), 32);
+ assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(30), 32);
+ assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(32), 48);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_padded_output_len_overflow() {
+ AesCbcPkcs7PaddedStub::padded_output_len(usize::MAX);
+ }
+
+ struct AesCbcPkcs7PaddedStub;
+
+ impl AesCbcPkcs7Padded for AesCbcPkcs7PaddedStub {
+ #[cfg(feature = "alloc")]
+ fn encrypt(_key: &Aes256Key, _iv: &AesCbcIv, _message: &[u8]) -> Vec<u8> {
+ unimplemented!()
+ }
+
+ fn encrypt_in_place(
+ _key: &Aes256Key,
+ _iv: &AesCbcIv,
+ _message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError> {
+ unimplemented!()
+ }
+
+ #[cfg(feature = "alloc")]
+ fn decrypt(
+ _key: &Aes256Key,
+ _iv: &AesCbcIv,
+ _ciphertext: &[u8],
+ ) -> Result<Vec<u8>, DecryptionError> {
+ unimplemented!()
+ }
+
+ fn decrypt_in_place(
+ _key: &Aes256Key,
+ _iv: &AesCbcIv,
+ _ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError> {
+ unimplemented!()
+ }
+ }
+}
diff --git a/nearby/crypto/crypto_provider/src/aes/ctr.rs b/nearby/crypto/crypto_provider/src/aes/ctr.rs
index 73d4f55..6779fe8 100644
--- a/nearby/crypto/crypto_provider/src/aes/ctr.rs
+++ b/nearby/crypto/crypto_provider/src/aes/ctr.rs
@@ -36,10 +36,8 @@
/// Build a `Self` from key material.
fn new(key: &Self::Key, nonce_and_counter: NonceAndCounter) -> Self;
- /// Encrypt the data in place, advancing the counter state appropriately.
- fn encrypt(&mut self, data: &mut [u8]);
- /// Decrypt the data in place, advancing the counter state appropriately.
- fn decrypt(&mut self, data: &mut [u8]);
+ /// Applies the key stream to the data in place, advancing the counter state appropriately.
+ fn apply_keystream(&mut self, data: &mut [u8]);
}
/// The combined nonce and counter that CTR increments and encrypts to form the keystream.
diff --git a/nearby/crypto/crypto_provider/src/aes/mod.rs b/nearby/crypto/crypto_provider/src/aes/mod.rs
index 83e48de..e359bad 100644
--- a/nearby/crypto/crypto_provider/src/aes/mod.rs
+++ b/nearby/crypto/crypto_provider/src/aes/mod.rs
@@ -20,7 +20,6 @@
pub mod ctr;
-#[cfg(feature = "alloc")]
pub mod cbc;
/// Block size in bytes for AES (and XTS-AES)
diff --git a/nearby/crypto/crypto_provider/src/ed25519.rs b/nearby/crypto/crypto_provider/src/ed25519.rs
index 48c2c50..b435ca2 100644
--- a/nearby/crypto/crypto_provider/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider/src/ed25519.rs
@@ -43,6 +43,59 @@
/// A byte buffer the size of a ed25519 `PrivateKey`.
pub type RawPrivateKey = [u8; PRIVATE_KEY_LENGTH];
+/// A permission token which may be supplied to methods which allow
+/// converting private keys to/from raw bytes.
+///
+/// In general, operations of this kind should only be done in
+/// development-tools, tests, or in credential storage layers
+/// to prevent accidental exposure of the private key.
+pub struct RawPrivateKeyPermit {
+ _marker: (),
+}
+
+impl RawPrivateKeyPermit {
+ pub(crate) fn new() -> Self {
+ Self { _marker: () }
+ }
+}
+
+#[cfg(feature = "raw_private_key_permit")]
+impl core::default::Default for RawPrivateKeyPermit {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// A crypto-provider-independent representation of the private
+/// key of an ed25519 key-pair, kept in such a way that
+/// it does not permit de-structuring it into raw bytes,
+/// nor constructing one from raw bytes.
+///
+/// Useful for when you want a data-structure to be
+/// crypto-provider independent and contain a private key.
+#[derive(Clone)]
+pub struct PrivateKey {
+ wrapped: RawPrivateKey,
+}
+
+impl PrivateKey {
+ /// Derives the public key corresponding to this private key.
+ pub fn derive_public_key<E: Ed25519Provider>(&self) -> E::PublicKey {
+ let key_pair = E::KeyPair::from_private_key(self);
+ key_pair.public()
+ }
+ /// Returns the raw bytes of this private key.
+ /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+ pub fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey {
+ self.wrapped
+ }
+ /// Constructs a private key from the raw bytes of the key.
+ /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+ pub fn from_raw_private_key(wrapped: RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self {
+ Self { wrapped }
+ }
+}
+
/// The keypair which includes both public and secret halves of an asymmetric key.
pub trait KeyPair: Sized {
/// The ed25519 public key, used when verifying a message
@@ -52,15 +105,37 @@
type Signature: Signature;
/// Returns the private key bytes of the `KeyPair`.
- /// This method should only ever be called by code which securely stores private credentials.
- fn private_key(&self) -> RawPrivateKey;
+ /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+ fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey;
/// Builds a key-pair from a `RawPrivateKey` array of bytes.
- /// This should only ever be called by code which securely stores private credentials.
- fn from_private_key(bytes: &RawPrivateKey) -> Self
+ /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+ fn from_raw_private_key(bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self
where
Self: Sized;
+ /// Returns the private key of the `KeyPair` in an opaque form.
+ fn private_key(&self) -> PrivateKey {
+ // We're okay to reach in and grab the bytes of the private key,
+ // since the way that we're exposing it would require a valid
+ // [`RawPrivateKeyPermit`] to extract them again.
+ let wrapped = self.raw_private_key(&RawPrivateKeyPermit::new());
+ PrivateKey { wrapped }
+ }
+
+ /// Builds a key-pair from a [`PrivateKey`], given in an opaque form.
+ fn from_private_key(private_key: &PrivateKey) -> Self
+ where
+ Self: Sized,
+ {
+ // We're okay to reach in and construct an instance from
+ // the bytes of the private key, since the way that they
+ // were originally expressed would still require a valid
+ // [`RawPrivateKeyPermit`] to access them.
+ let raw_private_key = &private_key.wrapped;
+ Self::from_raw_private_key(raw_private_key, &RawPrivateKeyPermit::new())
+ }
+
/// Sign the given message and return a digital signature
fn sign(&self, msg: &[u8]) -> Self::Signature;
diff --git a/nearby/crypto/crypto_provider/src/elliptic_curve.rs b/nearby/crypto/crypto_provider/src/elliptic_curve.rs
index d06a21d..d176769 100644
--- a/nearby/crypto/crypto_provider/src/elliptic_curve.rs
+++ b/nearby/crypto/crypto_provider/src/elliptic_curve.rs
@@ -12,12 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate alloc;
-
use core::fmt::Debug;
-use alloc::vec::Vec;
-
/// Marker trait for an elliptic curve used for diffie-hellman.
pub trait Curve {}
@@ -42,12 +38,16 @@
/// The random number generator to be used for generating a secret
type Rng: crate::CryptoRng;
+ /// The for encoded public key bytes, for example a `[u8; N]` array if the size is fixed, or
+ /// `ArrayVec<[u8; N]>` if the size is bounded but not fixed.
+ type EncodedPublicKey: AsRef<[u8]> + Debug;
+
/// Generates a new random ephemeral secret.
fn generate_random(rng: &mut Self::Rng) -> Self;
/// Returns the bytes of the public key for this ephemeral secret that is suitable for sending
/// over the wire for key exchange.
- fn public_key_bytes(&self) -> Vec<u8>;
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey;
/// Performs diffie-hellman key exchange using this ephemeral secret with the given public key
/// `other_pub`.
@@ -59,6 +59,8 @@
/// Trait for a public key used for elliptic curve diffie hellman.
pub trait PublicKey<E: Curve>: Sized + PartialEq + Debug {
+ /// The type for an encoded public key.
+ type EncodedPublicKey: AsRef<[u8]> + Debug;
/// The error type associated with Public Key.
type Error: Debug;
@@ -71,5 +73,5 @@
/// the sec1 encoding, may return equivalent but different byte-representations due to point
/// compression, so it is not necessarily true that `from_bytes(bytes)?.to_bytes() == bytes`
/// (but it is always true that `from_bytes(key.to_bytes())? == key`).
- fn to_bytes(&self) -> Vec<u8>;
+ fn to_bytes(&self) -> Self::EncodedPublicKey;
}
diff --git a/nearby/crypto/crypto_provider/src/lib.rs b/nearby/crypto/crypto_provider/src/lib.rs
index 624072a..0031ebb 100644
--- a/nearby/crypto/crypto_provider/src/lib.rs
+++ b/nearby/crypto/crypto_provider/src/lib.rs
@@ -48,6 +48,8 @@
/// mod containing traits for ed25519 key generation, signing, and verification
pub mod ed25519;
+pub use tinyvec;
+
/// Uber crypto trait which defines the traits for all crypto primitives as associated types
pub trait CryptoProvider: Clone + Debug + PartialEq + Eq + Send {
/// The Hkdf type which implements the hkdf trait
@@ -80,10 +82,13 @@
/// using SHA-512 (SHA-2) and Curve25519
type Ed25519: ed25519::Ed25519Provider;
/// The trait defining AES-128-GCM-SIV, a nonce-misuse resistant AEAD with a key size of 16 bytes.
- type Aes128GcmSiv: aead::aes_gcm_siv::AesGcmSiv<Key = Aes128Key>;
+ type Aes128GcmSiv: aead::AesGcmSiv + aead::AeadInit<Aes128Key>;
/// The trait defining AES-256-GCM-SIV, a nonce-misuse resistant AEAD with a key size of 32 bytes.
- type Aes256GcmSiv: aead::aes_gcm_siv::AesGcmSiv<Key = Aes256Key>;
-
+ type Aes256GcmSiv: aead::AesGcmSiv + aead::AeadInit<Aes256Key>;
+ /// The trait defining AES-128-GCM, an AEAD with a key size of 16 bytes.
+ type Aes128Gcm: aead::AesGcm + aead::AeadInit<Aes128Key>;
+ /// The trait defining AES-256-GCM, an AEAD with a key size of 32 bytes.
+ type Aes256Gcm: aead::AesGcm + aead::AeadInit<Aes256Key>;
/// The cryptographically secure random number generator
type CryptoRng: CryptoRng;
diff --git a/nearby/crypto/crypto_provider/src/p256.rs b/nearby/crypto/crypto_provider/src/p256.rs
index 90d3542..fd7b531 100644
--- a/nearby/crypto/crypto_provider/src/p256.rs
+++ b/nearby/crypto/crypto_provider/src/p256.rs
@@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate alloc;
+use tinyvec::ArrayVec;
use crate::elliptic_curve::{Curve, EcdhProvider, PublicKey};
-use alloc::vec::Vec;
use core::fmt::Debug;
/// Marker type for P256 implementation. This is used by EcdhProvider as its type parameter.
@@ -23,6 +22,24 @@
pub enum P256 {}
impl Curve for P256 {}
+/// Longest length for a sec-1 encoded P256 public key, which is the uncompressed format
+/// `04 || X || Y` as defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve Cryptography")
+/// standard.
+const P256_PUBLIC_KEY_MAX_LENGTH: usize = 65;
+
+/// Whether an elliptic curve point should be compressed or not.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PointCompression {
+ /// The elliptic curve point should be compressed (`02 || X` or `03 || X`),
+ /// as defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve
+ /// Cryptography").
+ Compressed,
+ /// The elliptic curve point should be uncompressed (`04 || X || Y`), as
+ /// defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve
+ /// Cryptography").
+ Uncompressed,
+}
+
/// Trait for a NIST-P256 public key.
pub trait P256PublicKey: Sized + PartialEq + Debug {
/// The error type associated with this implementation.
@@ -36,7 +53,10 @@
/// ("Elliptic Curve Cryptography") standard. Note that it is not necessarily true that
/// `from_sec1_bytes(bytes)?.to_sec1_bytes() == bytes` because of point compression. (But it is
/// always true that `from_sec1_bytes(key.to_sec1_bytes())? == key`).
- fn to_sec1_bytes(&self) -> Vec<u8>;
+ fn to_sec1_bytes(
+ &self,
+ point_compression: PointCompression,
+ ) -> ArrayVec<[u8; P256_PUBLIC_KEY_MAX_LENGTH]>;
/// Converts this public key's x and y coordinates on the elliptic curve to big endian octet
/// strings.
@@ -48,13 +68,14 @@
impl<P: P256PublicKey> PublicKey<P256> for P {
type Error = <Self as P256PublicKey>::Error;
+ type EncodedPublicKey = ArrayVec<[u8; P256_PUBLIC_KEY_MAX_LENGTH]>;
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
Self::from_sec1_bytes(bytes)
}
- fn to_bytes(&self) -> Vec<u8> {
- Self::to_sec1_bytes(self)
+ fn to_bytes(&self) -> Self::EncodedPublicKey {
+ Self::to_sec1_bytes(self, PointCompression::Uncompressed)
}
}