Project import generated by Copybara.
GitOrigin-RevId: 06b0c815d958bef0a60978d0766d65af839e37b6
Change-Id: Ifac0c45ae509ca8a8ed793fac5c981d4e23d3bf9
diff --git a/nearby/crypto/bssl-crypto/Cargo.toml b/nearby/crypto/bssl-crypto/Cargo.toml
deleted file mode 100644
index bfe3964..0000000
--- a/nearby/crypto/bssl-crypto/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "bssl-crypto"
-version.workspace = true
-edition.workspace = true
-publish.workspace = true
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
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)
}
}
diff --git a/nearby/crypto/crypto_provider_boringssl/.cargo/config.toml b/nearby/crypto/crypto_provider_boringssl/.cargo/config.toml
deleted file mode 100644
index f5ab7fa..0000000
--- a/nearby/crypto/crypto_provider_boringssl/.cargo/config.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-paths = [
- "../../../boringssl-build/boringssl/rust/bssl-crypto",
-]
\ No newline at end of file
diff --git a/nearby/crypto/crypto_provider_boringssl/Cargo.lock b/nearby/crypto/crypto_provider_boringssl/Cargo.lock
index 14402c1..7773e56 100644
--- a/nearby/crypto/crypto_provider_boringssl/Cargo.lock
+++ b/nearby/crypto/crypto_provider_boringssl/Cargo.lock
@@ -4,13 +4,20 @@
[[package]]
name = "base64"
-version = "0.13.1"
+version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "bssl-crypto"
version = "0.1.0"
+dependencies = [
+ "bssl-sys",
+]
+
+[[package]]
+name = "bssl-sys"
+version = "0.1.0"
[[package]]
name = "cfg-if"
@@ -21,6 +28,9 @@
[[package]]
name = "crypto_provider"
version = "0.1.0"
+dependencies = [
+ "tinyvec",
+]
[[package]]
name = "crypto_provider_boringssl"
@@ -28,18 +38,10 @@
dependencies = [
"bssl-crypto",
"crypto_provider",
- "crypto_provider_stubs",
"crypto_provider_test",
]
[[package]]
-name = "crypto_provider_stubs"
-version = "0.1.0"
-dependencies = [
- "crypto_provider",
-]
-
-[[package]]
name = "crypto_provider_test"
version = "0.1.0"
dependencies = [
@@ -56,9 +58,9 @@
[[package]]
name = "getrandom"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
@@ -79,24 +81,21 @@
[[package]]
name = "itoa"
-version = "1.0.6"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "libc"
-version = "0.2.144"
+version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "log"
-version = "0.4.17"
+version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "ppv-lite86"
@@ -106,18 +105,18 @@
[[package]]
name = "proc-macro2"
-version = "1.0.56"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.27"
+version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@@ -197,14 +196,14 @@
[[package]]
name = "rstest_reuse"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073"
+checksum = "88530b681abe67924d42cca181d070e3ac20e0740569441a9e35a7cedd2b34a4"
dependencies = [
"quote",
"rand",
"rustc_version",
- "syn 1.0.109",
+ "syn 2.0.29",
]
[[package]]
@@ -218,41 +217,41 @@
[[package]]
name = "ryu"
-version = "1.0.13"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "semver"
-version = "1.0.17"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "serde"
-version = "1.0.162"
+version = "1.0.187"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
+checksum = "30a7fe14252655bd1e578af19f5fa00fe02fd0013b100ca6b49fde31c41bae4c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.162"
+version = "1.0.187"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
+checksum = "e46b2a6ca578b3f1d4501b12f78ed4692006d79d82a1a7c561c12dbc3d625eb8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.29",
]
[[package]]
name = "serde_json"
-version = "1.0.96"
+version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
+checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [
"itoa",
"ryu",
@@ -272,9 +271,9 @@
[[package]]
name = "syn"
-version = "2.0.15"
+version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [
"proc-macro2",
"quote",
@@ -290,10 +289,16 @@
]
[[package]]
-name = "unicode-ident"
-version = "1.0.8"
+name = "tinyvec"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "wasi"
@@ -303,9 +308,9 @@
[[package]]
name = "wycheproof"
-version = "0.4.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "183c789620c674b79dac33cd3aadb6c8006b66cba6a680402235aaebc743e3df"
+checksum = "e639f57253b80c6584b378011aec0fed61c4c21d7a4b97c4d9d7eaf35ca77d12"
dependencies = [
"base64",
"hex",
diff --git a/nearby/crypto/crypto_provider_boringssl/Cargo.toml b/nearby/crypto/crypto_provider_boringssl/Cargo.toml
index 24ce66c..fb3bfdf 100644
--- a/nearby/crypto/crypto_provider_boringssl/Cargo.toml
+++ b/nearby/crypto/crypto_provider_boringssl/Cargo.toml
@@ -6,10 +6,9 @@
[dependencies]
crypto_provider = { path = "../crypto_provider", features = ["alloc", "std"] }
-crypto_provider_stubs = { path = "../crypto_provider_stubs" }
-# Note: before this crate will work you need to run `scripts/prepare-boringssl.sh`
-bssl-crypto = {path = "../bssl-crypto"}
+# Note: before this crate will work you need to run `cargo run -p build_scripts -- build-boringssl`
+bssl-crypto = {path = "../../../third_party/boringssl/rust/bssl-crypto"}
[dev-dependencies]
crypto_provider_test = {path = "../crypto_provider_test"}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm.rs b/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm.rs
new file mode 100644
index 0000000..03bb087
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm.rs
@@ -0,0 +1,89 @@
+// 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;
+use bssl_crypto::aead::Aead as _;
+use crypto_provider::aead::{Aead, AeadError, AeadInit};
+use crypto_provider::aes::{Aes128Key, Aes256Key, AesKey};
+
+pub struct AesGcm(bssl_crypto::aead::AesGcm);
+
+impl AeadInit<Aes128Key> for AesGcm {
+ fn new(key: &Aes128Key) -> Self {
+ Self(bssl_crypto::aead::new_aes_128_gcm(key.as_array()))
+ }
+}
+
+impl AeadInit<Aes256Key> for AesGcm {
+ fn new(key: &Aes256Key) -> Self {
+ Self(bssl_crypto::aead::new_aes_256_gcm(key.as_array()))
+ }
+}
+
+impl crypto_provider::aead::AesGcm for AesGcm {}
+
+impl Aead for AesGcm {
+ const TAG_SIZE: usize = 16;
+ type Nonce = [u8; 12];
+ type Tag = [u8; 16];
+
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0.encrypt(msg, aad, nonce).map_err(|_| AeadError)
+ }
+
+ fn encrypt_detached(
+ &self,
+ _msg: &mut [u8],
+ _aad: &[u8],
+ _nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
+ unimplemented!("Not yet supported by boringssl")
+ }
+
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0.decrypt(msg, aad, nonce).map_err(|_| AeadError)
+ }
+
+ fn decrypt_detached(
+ &self,
+ _msg: &mut [u8],
+ _aad: &[u8],
+ _nonce: &Self::Nonce,
+ _tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
+ unimplemented!("Not yet supported by boringssl")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use core::marker::PhantomData;
+
+ use crypto_provider_test::aead::aes_gcm::*;
+ use crypto_provider_test::aes::*;
+
+ use super::*;
+
+ #[apply(aes_128_gcm_test_cases)]
+ fn aes_gcm_128_test(testcase: CryptoProviderTestCase<AesGcm>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_gcm_test_cases)]
+ fn aes_gcm_256_test(testcase: CryptoProviderTestCase<AesGcm>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm_siv.rs
new file mode 100644
index 0000000..d1fb0e7
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/aead/aes_gcm_siv.rs
@@ -0,0 +1,88 @@
+// 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;
+use bssl_crypto::aead::Aead as _;
+use crypto_provider::aead::{Aead, AeadError, AeadInit};
+use crypto_provider::aes::{Aes128Key, Aes256Key, AesKey};
+
+pub struct AesGcmSiv(bssl_crypto::aead::AesGcmSiv);
+
+impl AeadInit<Aes128Key> for AesGcmSiv {
+ fn new(key: &Aes128Key) -> Self {
+ Self(bssl_crypto::aead::new_aes_128_gcm_siv(key.as_array()))
+ }
+}
+
+impl AeadInit<Aes256Key> for AesGcmSiv {
+ fn new(key: &Aes256Key) -> Self {
+ Self(bssl_crypto::aead::new_aes_256_gcm_siv(key.as_array()))
+ }
+}
+
+impl crypto_provider::aead::AesGcmSiv for AesGcmSiv {}
+
+impl Aead for AesGcmSiv {
+ const TAG_SIZE: usize = 16;
+ type Nonce = [u8; 12];
+ type Tag = [u8; 16];
+
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0.encrypt(msg, aad, nonce).map_err(|_| AeadError)
+ }
+
+ fn encrypt_detached(
+ &self,
+ _msg: &mut [u8],
+ _aad: &[u8],
+ _nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
+ unimplemented!("Not yet supported by boringssl")
+ }
+
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0.decrypt(msg, aad, nonce).map_err(|_| AeadError)
+ }
+
+ fn decrypt_detached(
+ &self,
+ _msg: &mut [u8],
+ _aad: &[u8],
+ _nonce: &Self::Nonce,
+ _tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
+ unimplemented!("Not yet supported by boringssl")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use core::marker::PhantomData;
+
+ use crypto_provider_test::aead::aes_gcm_siv::*;
+ use crypto_provider_test::aes::*;
+
+ use super::*;
+
+ #[apply(aes_128_gcm_siv_test_cases)]
+ fn aes_gcm_siv_128_test(testcase: CryptoProviderTestCase<AesGcmSiv>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_gcm_siv_test_cases)]
+ fn aes_gcm_siv_256_test(testcase: CryptoProviderTestCase<AesGcmSiv>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/bssl-crypto/src/lib.rs b/nearby/crypto/crypto_provider_boringssl/src/aead/mod.rs
similarity index 73%
rename from nearby/crypto/bssl-crypto/src/lib.rs
rename to nearby/crypto/crypto_provider_boringssl/src/aead/mod.rs
index 89e6968..424f16e 100644
--- a/nearby/crypto/bssl-crypto/src/lib.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/aead/mod.rs
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//! Placeholder crate to satisfy cargo. If actually using boring ssl, please run the
-//! `build-boringssl` subcommand of the top level crate.
+pub(crate) mod aes_gcm;
+pub(crate) mod aes_gcm_siv;
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aes/cbc.rs b/nearby/crypto/crypto_provider_boringssl/src/aes/cbc.rs
new file mode 100644
index 0000000..4d3fd3f
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/aes/cbc.rs
@@ -0,0 +1,81 @@
+// 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;
+use bssl_crypto::cipher::BlockCipher;
+use crypto_provider::{
+ aes::{
+ cbc::{AesCbcIv, DecryptionError, EncryptionError},
+ Aes256Key, AesKey,
+ },
+ tinyvec::SliceVec,
+};
+
+/// BoringSSL implementation of AES-CBC with PKCS7 padding
+pub enum AesCbcPkcs7Padded {}
+impl crypto_provider::aes::cbc::AesCbcPkcs7Padded for AesCbcPkcs7Padded {
+ #[allow(clippy::expect_used)]
+ fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8> {
+ let encryptor = bssl_crypto::cipher::aes_cbc::Aes256Cbc::new_encrypt(key.as_array(), iv);
+ encryptor.encrypt_padded(message).expect("Encrypting AES-CBC should be infallible")
+ }
+
+ fn encrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError> {
+ let result = Self::encrypt(key, iv, message);
+ if message.capacity() < result.len() {
+ return Err(EncryptionError::PaddingFailed);
+ }
+ message.clear();
+ message.extend_from_slice(&result);
+ Ok(())
+ }
+
+ fn decrypt(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &[u8],
+ ) -> Result<Vec<u8>, DecryptionError> {
+ let decryptor = bssl_crypto::cipher::aes_cbc::Aes256Cbc::new_decrypt(key.as_array(), iv);
+ decryptor.decrypt_padded(ciphertext).map_err(|_| DecryptionError::BadPadding)
+ }
+
+ fn decrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError> {
+ Self::decrypt(key, iv, ciphertext).map(|result| {
+ ciphertext.clear();
+ ciphertext.extend_from_slice(&result);
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::AesCbcPkcs7Padded;
+ use core::marker::PhantomData;
+ use crypto_provider_test::aes::cbc::*;
+
+ #[apply(aes_256_cbc_test_cases)]
+ fn aes_256_cbc_test(testcase: CryptoProviderTestCase<AesCbcPkcs7Padded>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aes/ctr.rs b/nearby/crypto/crypto_provider_boringssl/src/aes/ctr.rs
new file mode 100644
index 0000000..c13ab31
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/aes/ctr.rs
@@ -0,0 +1,74 @@
+// 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.
+
+use bssl_crypto::cipher::StreamCipher;
+use crypto_provider::aes::{ctr::NonceAndCounter, Aes128Key, Aes256Key, AesKey};
+
+/// BoringSSL implementation of AES-CTR 128.
+pub struct AesCtr128(bssl_crypto::cipher::aes_ctr::Aes128Ctr);
+
+impl crypto_provider::aes::ctr::AesCtr for AesCtr128 {
+ type Key = Aes128Key;
+
+ fn new(key: &Self::Key, nonce_and_counter: NonceAndCounter) -> Self {
+ Self(bssl_crypto::cipher::aes_ctr::Aes128Ctr::new(
+ key.as_array(),
+ &nonce_and_counter.as_block_array(),
+ ))
+ }
+
+ #[allow(clippy::expect_used)]
+ fn apply_keystream(&mut self, data: &mut [u8]) {
+ assert!(data.len() < i32::MAX as usize);
+ self.0.apply_keystream(data).expect("Data length should fit inside of a i32")
+ }
+}
+
+/// BoringSSL implementation of AES-CTR 256.
+pub struct AesCtr256(bssl_crypto::cipher::aes_ctr::Aes256Ctr);
+
+impl crypto_provider::aes::ctr::AesCtr for AesCtr256 {
+ type Key = Aes256Key;
+
+ fn new(key: &Self::Key, nonce_and_counter: NonceAndCounter) -> Self {
+ Self(bssl_crypto::cipher::aes_ctr::Aes256Ctr::new(
+ key.as_array(),
+ &nonce_and_counter.as_block_array(),
+ ))
+ }
+
+ #[allow(clippy::expect_used)]
+ fn apply_keystream(&mut self, data: &mut [u8]) {
+ assert!(data.len() < i32::MAX as usize);
+ self.0.apply_keystream(data).expect("Data length should fit inside of a i32")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use core::marker::PhantomData;
+ use crypto_provider_test::aes::ctr::*;
+ use crypto_provider_test::aes::*;
+
+ #[apply(aes_128_ctr_test_cases)]
+ fn aes_128_ctr_test(testcase: CryptoProviderTestCase<AesCtr128>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_ctr_test_cases)]
+ fn aes_256_ctr_test(testcase: CryptoProviderTestCase<AesCtr256>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aes.rs b/nearby/crypto/crypto_provider_boringssl/src/aes/mod.rs
similarity index 97%
rename from nearby/crypto/crypto_provider_boringssl/src/aes.rs
rename to nearby/crypto/crypto_provider_boringssl/src/aes/mod.rs
index 88bfeac..d5cbe58 100644
--- a/nearby/crypto/crypto_provider_boringssl/src/aes.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/aes/mod.rs
@@ -17,6 +17,12 @@
Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, AesKey,
};
+/// AES_CTR implementations.
+pub mod ctr;
+
+/// AES_CBC implementations.
+pub mod cbc;
+
/// BoringSSL AES-128 operations
pub struct Aes128;
impl Aes for Aes128 {
diff --git a/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs b/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs
index 7c671ae..b5c374a 100644
--- a/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs
@@ -13,7 +13,8 @@
// limitations under the License.
use crypto_provider::ed25519::{
- InvalidBytes, RawPrivateKey, RawPublicKey, RawSignature, Signature as _, SignatureError,
+ InvalidBytes, RawPrivateKey, RawPrivateKeyPermit, RawPublicKey, RawSignature, Signature as _,
+ SignatureError,
};
pub struct Ed25519;
@@ -30,11 +31,11 @@
type PublicKey = PublicKey;
type Signature = Signature;
- fn private_key(&self) -> RawPrivateKey {
+ fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey {
self.0.to_seed()
}
- fn from_private_key(bytes: &RawPrivateKey) -> Self
+ fn from_raw_private_key(bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self
where
Self: Sized,
{
diff --git a/nearby/crypto/crypto_provider_boringssl/src/lib.rs b/nearby/crypto/crypto_provider_boringssl/src/lib.rs
index 3b78898..75758b6 100644
--- a/nearby/crypto/crypto_provider_boringssl/src/lib.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/lib.rs
@@ -21,14 +21,12 @@
clippy::expect_used
)]
-//! Crate which provides impls for CryptoProvider backed by BoringSSL.
-
-use bssl_crypto::digest::{Sha256, Sha512};
+//! Crate which provides impls for CryptoProvider backed by BoringSSL
+//!
use bssl_crypto::rand::rand_bytes;
use crypto_provider::{CryptoProvider, CryptoRng};
-use crypto_provider_stubs::*;
-/// Implementation of `crypto_provider::aes` types using BoringSSL.
+/// Implementation of `crypto_provider::aes` types using BoringSSL
pub mod aes;
/// Implementations of crypto_provider::hkdf traits backed by BoringSSL
@@ -40,31 +38,45 @@
/// Implementations of crypto_provider::ed25519 traits backed by BoringSSL
mod ed25519;
+/// Implementations of crypto_provider::aead traits backed by BoringSSL
+mod aead;
+
+/// Implementations of crypto_provider::p256 traits backed by BoringSSL
+mod p256;
+
+/// Implementations of crypto_provider::x25519 traits backed by BoringSSL
+mod x25519;
+
+/// Implementations of crypto_provider::sha2 traits backed by BoringSSL
+mod sha2;
+
/// The BoringSSL backed struct which implements CryptoProvider
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct Boringssl;
impl CryptoProvider for Boringssl {
- type HkdfSha256 = hkdf::Hkdf<Sha256>;
+ type HkdfSha256 = hkdf::Hkdf<bssl_crypto::digest::Sha256>;
type HmacSha256 = hmac::HmacSha256;
- type HkdfSha512 = hkdf::Hkdf<Sha512>;
+ type HkdfSha512 = hkdf::Hkdf<bssl_crypto::digest::Sha512>;
type HmacSha512 = hmac::HmacSha512;
- type AesCbcPkcs7Padded = AesCbcPkcs7PaddedStubs;
- type X25519 = X25519Stubs;
- type P256 = P256Stubs;
- type Sha256 = Sha2Stubs;
- type Sha512 = Sha2Stubs;
+ type AesCbcPkcs7Padded = aes::cbc::AesCbcPkcs7Padded;
+ type X25519 = x25519::X25519Ecdh;
+ type P256 = p256::P256Ecdh;
+ type Sha256 = sha2::Sha256;
+ type Sha512 = sha2::Sha512;
type Aes128 = aes::Aes128;
type Aes256 = aes::Aes256;
- type AesCtr128 = Aes128Stubs;
- type AesCtr256 = Aes256Stubs;
+ type AesCtr128 = aes::ctr::AesCtr128;
+ type AesCtr256 = aes::ctr::AesCtr256;
type Ed25519 = ed25519::Ed25519;
- type Aes128GcmSiv = Aes128Stubs;
- type Aes256GcmSiv = Aes256Stubs;
+ type Aes128GcmSiv = aead::aes_gcm_siv::AesGcmSiv;
+ type Aes256GcmSiv = aead::aes_gcm_siv::AesGcmSiv;
+ type Aes128Gcm = aead::aes_gcm::AesGcm;
+ type Aes256Gcm = aead::aes_gcm::AesGcm;
type CryptoRng = BoringSslRng;
- fn constant_time_eq(_a: &[u8], _b: &[u8]) -> bool {
- unimplemented!()
+ fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
+ bssl_crypto::mem::crypto_memcmp(a, b)
}
}
@@ -86,3 +98,17 @@
rand_bytes(dest)
}
}
+
+#[cfg(test)]
+mod tests {
+ use core::marker::PhantomData;
+ use crypto_provider_test::prelude::*;
+ use crypto_provider_test::sha2::*;
+
+ use crate::Boringssl;
+
+ #[apply(sha2_test_cases)]
+ fn sha2_tests(testcase: CryptoProviderTestCase<Boringssl>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/p256.rs b/nearby/crypto/crypto_provider_boringssl/src/p256.rs
new file mode 100644
index 0000000..7fefecd
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/p256.rs
@@ -0,0 +1,117 @@
+// 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 bssl_crypto::ecdh::{PrivateKey, PublicKey};
+use crypto_provider::{
+ elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey as _},
+ p256::{PointCompression, P256},
+ tinyvec::ArrayVec,
+};
+
+/// Implementation of NIST-P256 using bssl-crypto crate.
+pub struct P256Ecdh;
+
+impl EcdhProvider<P256> for P256Ecdh {
+ type PublicKey = P256PublicKey;
+ type EphemeralSecret = P256EphemeralSecret;
+ type SharedSecret = [u8; 32];
+}
+
+/// A NIST-P256 public key.
+#[derive(Debug, PartialEq, Eq)]
+pub struct P256PublicKey(PublicKey<bssl_crypto::ecdh::P256>);
+impl crypto_provider::p256::P256PublicKey for P256PublicKey {
+ type Error = bssl_crypto::ecdh::Error;
+
+ fn from_sec1_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
+ PublicKey::try_from(bytes).map(Self)
+ }
+
+ fn to_sec1_bytes(&self, point_compression: PointCompression) -> ArrayVec<[u8; 65]> {
+ match point_compression {
+ PointCompression::Compressed => unimplemented!(),
+ PointCompression::Uncompressed => {
+ let mut bytes = ArrayVec::<[u8; 65]>::new();
+ bytes.extend_from_slice(&self.0.to_vec());
+ bytes
+ }
+ }
+ }
+
+ #[allow(clippy::expect_used)]
+ fn to_affine_coordinates(&self) -> Result<([u8; 32], [u8; 32]), Self::Error> {
+ Ok(self.0.to_affine_coordinates())
+ }
+ fn from_affine_coordinates(x: &[u8; 32], y: &[u8; 32]) -> Result<Self, Self::Error> {
+ PublicKey::<bssl_crypto::ecdh::P256>::from_affine_coordinates(x, y).map(Self)
+ }
+}
+
+/// Ephemeral secrect for use in a P256 Diffie-Hellman
+pub struct P256EphemeralSecret {
+ secret: PrivateKey<bssl_crypto::ecdh::P256>,
+}
+
+impl EphemeralSecret<P256> for P256EphemeralSecret {
+ type Impl = P256Ecdh;
+ type Error = bssl_crypto::ecdh::Error;
+ type Rng = ();
+ type EncodedPublicKey =
+ <P256PublicKey as crypto_provider::elliptic_curve::PublicKey<P256>>::EncodedPublicKey;
+
+ fn generate_random(_rng: &mut Self::Rng) -> Self {
+ Self { secret: PrivateKey::generate() }
+ }
+
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
+ P256PublicKey((&self.secret).into()).to_bytes()
+ }
+
+ fn diffie_hellman(
+ self,
+ other_pub: &P256PublicKey,
+ ) -> Result<<Self::Impl as EcdhProvider<P256>>::SharedSecret, Self::Error> {
+ let shared_secret = self.secret.diffie_hellman(&other_pub.0)?;
+ let bytes: <Self::Impl as EcdhProvider<P256>>::SharedSecret = shared_secret.to_bytes();
+ Ok(bytes)
+ }
+}
+
+#[cfg(test)]
+impl crypto_provider_test::elliptic_curve::EphemeralSecretForTesting<P256> for P256EphemeralSecret {
+ #[allow(clippy::unwrap_used)]
+ fn from_private_components(
+ private_bytes: &[u8; 32],
+ _public_key: &P256PublicKey,
+ ) -> Result<Self, Self::Error> {
+ Ok(Self { secret: PrivateKey::from_private_bytes(private_bytes).unwrap() })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::P256Ecdh;
+ use core::marker::PhantomData;
+ use crypto_provider_test::p256::*;
+
+ #[apply(p256_test_cases)]
+ fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh>, name: &str) {
+ if name == "to_bytes_compressed" {
+ return; // EC point compression not supported by bssl-crypto yet
+ }
+ testcase(PhantomData::<P256Ecdh>)
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/sha2.rs b/nearby/crypto/crypto_provider_boringssl/src/sha2.rs
new file mode 100644
index 0000000..d95294d
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/sha2.rs
@@ -0,0 +1,35 @@
+// 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.
+
+/// BoringSSL implementation for SHA256
+pub struct Sha256;
+
+impl crypto_provider::sha2::Sha256 for Sha256 {
+ fn sha256(input: &[u8]) -> [u8; 32] {
+ let mut digest = bssl_crypto::digest::Sha256::new_digest();
+ digest.update(input);
+ digest.finalize()
+ }
+}
+
+/// BoringSSL implementation for SHA512
+pub struct Sha512;
+
+impl crypto_provider::sha2::Sha512 for Sha512 {
+ fn sha512(input: &[u8]) -> [u8; 64] {
+ let mut digest = bssl_crypto::digest::Sha512::new_digest();
+ digest.update(input);
+ digest.finalize()
+ }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/x25519.rs b/nearby/crypto/crypto_provider_boringssl/src/x25519.rs
new file mode 100644
index 0000000..58d040b
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/x25519.rs
@@ -0,0 +1,102 @@
+// 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.
+
+use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey};
+use crypto_provider::x25519::X25519;
+
+/// The BoringSSL implementation of X25519 ECDH.
+pub struct X25519Ecdh;
+
+impl EcdhProvider<X25519> for X25519Ecdh {
+ type PublicKey = X25519PublicKey;
+ type EphemeralSecret = X25519EphemeralSecret;
+ type SharedSecret = [u8; 32];
+}
+
+/// A X25519 ephemeral secret used for Diffie-Hellman.
+pub struct X25519EphemeralSecret {
+ secret: bssl_crypto::x25519::PrivateKey,
+}
+
+impl EphemeralSecret<X25519> for X25519EphemeralSecret {
+ type Impl = X25519Ecdh;
+ type Error = bssl_crypto::x25519::DiffieHellmanError;
+ type Rng = ();
+ type EncodedPublicKey = [u8; 32];
+
+ fn generate_random(_rng: &mut Self::Rng) -> Self {
+ Self { secret: bssl_crypto::x25519::PrivateKey::generate() }
+ }
+
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
+ let pubkey: bssl_crypto::x25519::PublicKey = (&self.secret).into();
+ pubkey.to_bytes()
+ }
+
+ fn diffie_hellman(
+ self,
+ other_pub: &<X25519Ecdh as EcdhProvider<X25519>>::PublicKey,
+ ) -> Result<<X25519Ecdh as EcdhProvider<X25519>>::SharedSecret, Self::Error> {
+ self.secret.diffie_hellman(&other_pub.0).map(|secret| secret.to_bytes())
+ }
+}
+
+#[cfg(test)]
+impl crypto_provider_test::elliptic_curve::EphemeralSecretForTesting<X25519>
+ for X25519EphemeralSecret
+{
+ fn from_private_components(
+ private_bytes: &[u8; 32],
+ _public_key: &X25519PublicKey,
+ ) -> Result<Self, Self::Error> {
+ Ok(Self { secret: bssl_crypto::x25519::PrivateKey::from_private_bytes(private_bytes) })
+ }
+}
+
+/// A X25519 public key.
+#[derive(Debug, PartialEq, Eq)]
+pub struct X25519PublicKey(bssl_crypto::x25519::PublicKey);
+
+impl PublicKey<X25519> for X25519PublicKey {
+ type Error = Error;
+ type EncodedPublicKey = [u8; 32];
+
+ fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
+ let byte_arr: [u8; 32] = bytes.try_into().map_err(|_| Error::WrongSize)?;
+ Ok(Self(bssl_crypto::x25519::PublicKey::from(&byte_arr)))
+ }
+
+ fn to_bytes(&self) -> Self::EncodedPublicKey {
+ self.0.to_bytes()
+ }
+}
+
+/// Error type for the BoringSSL implementation of x25519.
+#[derive(Debug)]
+pub enum Error {
+ /// Unexpected size for the given input.
+ WrongSize,
+}
+
+#[cfg(test)]
+mod tests {
+ use super::X25519Ecdh;
+ use core::marker::PhantomData;
+ use crypto_provider_test::x25519::*;
+
+ #[apply(x25519_test_cases)]
+ fn x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh>) {
+ testcase(PhantomData::<X25519Ecdh>)
+ }
+}
diff --git a/nearby/crypto/crypto_provider_default/src/lib.rs b/nearby/crypto/crypto_provider_default/src/lib.rs
index 4b1b01e..b880ba8 100644
--- a/nearby/crypto/crypto_provider_default/src/lib.rs
+++ b/nearby/crypto/crypto_provider_default/src/lib.rs
@@ -15,6 +15,10 @@
//! Provides multiple implementations of CryptoProvider through the same struct, configurable by
//! feature flag.
+#![no_std]
+#![forbid(unsafe_code)]
+#![deny(missing_docs)]
+
cfg_if::cfg_if! {
if #[cfg(feature = "rustcrypto")] {
pub use crypto_provider_rustcrypto::RustCrypto as CryptoProviderImpl;
diff --git a/nearby/crypto/crypto_provider_openssl/src/aes.rs b/nearby/crypto/crypto_provider_openssl/src/aes.rs
index f5d5b00..c2ac5b1 100644
--- a/nearby/crypto/crypto_provider_openssl/src/aes.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/aes.rs
@@ -26,10 +26,13 @@
use openssl::symm::{Cipher, Crypter, Mode};
-use crypto_provider::aes::{
- cbc::{AesCbcIv, DecryptionError},
- ctr::NonceAndCounter,
- Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, AesKey,
+use crypto_provider::{
+ aes::{
+ cbc::{AesCbcIv, DecryptionError, EncryptionError},
+ ctr::NonceAndCounter,
+ Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, AesKey,
+ },
+ tinyvec::SliceVec,
};
/// Uber struct which contains impls for AES-128 fns
@@ -126,7 +129,23 @@
impl crypto_provider::aes::cbc::AesCbcPkcs7Padded for OpenSslAesCbcPkcs7 {
fn encrypt(key: &crypto_provider::aes::Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8> {
openssl::symm::encrypt(Cipher::aes_256_cbc(), key.as_slice(), Some(iv.as_slice()), message)
- .unwrap()
+ // The output buffer is allocated by the openssl crate and guarantees to have enough
+ // space to hold the output value and does not overlap with the input slice.
+ .expect("encrypt should always succeed")
+ }
+
+ fn encrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError> {
+ let encrypted = Self::encrypt(key, iv, message);
+ if encrypted.len() > message.capacity() {
+ return Err(EncryptionError::PaddingFailed);
+ }
+ message.clear();
+ message.extend_from_slice(&encrypted);
+ Ok(())
}
fn decrypt(
@@ -142,12 +161,22 @@
)
.map_err(|_| DecryptionError::BadPadding)
}
+
+ fn decrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError> {
+ Self::decrypt(key, iv, ciphertext).map(|result| {
+ ciphertext.clear();
+ ciphertext.extend_from_slice(&result);
+ })
+ }
}
/// OpenSSL implementation of AES-CTR-128
pub struct OpenSslAesCtr128 {
enc_cipher: Crypter,
- dec_cipher: Crypter,
}
impl crypto_provider::aes::ctr::AesCtr for OpenSslAesCtr128 {
@@ -161,33 +190,19 @@
Some(&nonce_and_counter.as_block_array()),
)
.unwrap(),
- dec_cipher: Crypter::new(
- Cipher::aes_128_ctr(),
- Mode::Decrypt,
- key.as_slice(),
- Some(&nonce_and_counter.as_block_array()),
- )
- .unwrap(),
}
}
- fn encrypt(&mut self, data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
let mut in_slice = vec![0u8; data.len()];
in_slice.copy_from_slice(data);
let _ = self.enc_cipher.update(&in_slice, data);
}
-
- fn decrypt(&mut self, data: &mut [u8]) {
- let mut in_slice = vec![0u8; data.len()];
- in_slice.copy_from_slice(data);
- let _ = self.dec_cipher.update(&in_slice, data);
- }
}
/// OpenSSL implementation of AES-CTR-256
pub struct OpenSslAesCtr256 {
enc_cipher: Crypter,
- dec_cipher: Crypter,
}
impl crypto_provider::aes::ctr::AesCtr for OpenSslAesCtr256 {
@@ -201,27 +216,14 @@
Some(&nonce_and_counter.as_block_array()),
)
.unwrap(),
- dec_cipher: Crypter::new(
- Cipher::aes_256_ctr(),
- Mode::Decrypt,
- key.as_slice(),
- Some(&nonce_and_counter.as_block_array()),
- )
- .unwrap(),
}
}
- fn encrypt(&mut self, data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
let mut in_slice = vec![0u8; data.len()];
in_slice.copy_from_slice(data);
let _ = self.enc_cipher.update(&in_slice, data);
}
-
- fn decrypt(&mut self, data: &mut [u8]) {
- let mut in_slice = vec![0u8; data.len()];
- in_slice.copy_from_slice(data);
- let _ = self.dec_cipher.update(&in_slice, data);
- }
}
#[cfg(test)]
diff --git a/nearby/crypto/crypto_provider_openssl/src/ed25519.rs b/nearby/crypto/crypto_provider_openssl/src/ed25519.rs
index 110daf2..111348a 100644
--- a/nearby/crypto/crypto_provider_openssl/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/ed25519.rs
@@ -13,7 +13,8 @@
// limitations under the License.
use crypto_provider::ed25519::{
- InvalidBytes, RawPrivateKey, RawPublicKey, RawSignature, Signature as _, SignatureError,
+ InvalidBytes, RawPrivateKey, RawPrivateKeyPermit, RawPublicKey, RawSignature, Signature as _,
+ SignatureError,
};
use openssl::pkey::{Id, PKey, Private};
use openssl::sign::{Signer, Verifier};
@@ -32,7 +33,7 @@
type PublicKey = PublicKey;
type Signature = Signature;
- fn private_key(&self) -> RawPrivateKey {
+ fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey {
let private_key = self.0.raw_private_key().unwrap();
let mut public_key = self.0.raw_public_key().unwrap();
let mut result = private_key;
@@ -40,7 +41,7 @@
result.try_into().unwrap()
}
- fn from_private_key(bytes: &RawPrivateKey) -> Self {
+ fn from_raw_private_key(bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self {
Self(PKey::private_key_from_raw_bytes(bytes, Id::ED25519).unwrap())
}
diff --git a/nearby/crypto/crypto_provider_openssl/src/lib.rs b/nearby/crypto/crypto_provider_openssl/src/lib.rs
index d8157d2..8d1db1d 100644
--- a/nearby/crypto/crypto_provider_openssl/src/lib.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/lib.rs
@@ -82,6 +82,8 @@
type Ed25519 = ed25519::Ed25519;
type Aes128GcmSiv = crypto_provider_stubs::Aes128Stubs;
type Aes256GcmSiv = crypto_provider_stubs::Aes256Stubs;
+ type Aes128Gcm = crypto_provider_stubs::Aes128Stubs;
+ type Aes256Gcm = crypto_provider_stubs::Aes256Stubs;
type CryptoRng = OpenSslRng;
fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
@@ -113,7 +115,7 @@
use core::marker::PhantomData;
use crypto_provider_test::sha2::*;
- use crypto_provider_test::*;
+ use crypto_provider_test::{prelude::*, *};
use crate::Openssl;
diff --git a/nearby/crypto/crypto_provider_openssl/src/p256.rs b/nearby/crypto/crypto_provider_openssl/src/p256.rs
index 2f5b0b1..17dd6ce 100644
--- a/nearby/crypto/crypto_provider_openssl/src/p256.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/p256.rs
@@ -12,8 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret};
-use crypto_provider::p256::P256;
+use crypto_provider::{
+ elliptic_curve::{EcdhProvider, EphemeralSecret},
+ p256::{PointCompression, P256},
+ tinyvec::ArrayVec,
+};
use openssl::bn::{BigNum, BigNumContext};
use openssl::derive::Deriver;
use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
@@ -65,15 +68,24 @@
Ok(Self(eckey.try_into()?))
}
- fn to_sec1_bytes(&self) -> Vec<u8> {
+ fn to_sec1_bytes(&self, point_compression: PointCompression) -> ArrayVec<[u8; 65]> {
+ let point_conversion_form = match point_compression {
+ PointCompression::Compressed => PointConversionForm::COMPRESSED,
+ PointCompression::Uncompressed => PointConversionForm::UNCOMPRESSED,
+ };
let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let mut bncontext = BigNumContext::new().unwrap();
- self.0
- .ec_key()
- .unwrap()
- .public_key()
- .to_bytes(&ecgroup, PointConversionForm::COMPRESSED, &mut bncontext)
- .unwrap()
+ let mut bytes = ArrayVec::<[u8; 65]>::new();
+ bytes.extend_from_slice(
+ &self
+ .0
+ .ec_key()
+ .unwrap()
+ .public_key()
+ .to_bytes(&ecgroup, point_conversion_form, &mut bncontext)
+ .unwrap(),
+ );
+ bytes
}
fn from_affine_coordinates(x: &[u8; 32], y: &[u8; 32]) -> Result<Self, Self::Error> {
@@ -115,6 +127,7 @@
type Impl = P256Ecdh;
type Error = Error;
type Rng = ();
+ type EncodedPublicKey = ArrayVec<[u8; 65]>;
fn generate_random(_rng: &mut Self::Rng) -> Self {
let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
@@ -122,15 +135,20 @@
Self(eckey.try_into().unwrap())
}
- fn public_key_bytes(&self) -> Vec<u8> {
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let mut bncontext = BigNumContext::new().unwrap();
- self.0
- .ec_key()
- .unwrap()
- .public_key()
- .to_bytes(&ecgroup, PointConversionForm::COMPRESSED, &mut bncontext)
- .unwrap()
+ let mut bytes = Self::EncodedPublicKey::new();
+ bytes.extend_from_slice(
+ &self
+ .0
+ .ec_key()
+ .unwrap()
+ .public_key()
+ .to_bytes(&ecgroup, PointConversionForm::COMPRESSED, &mut bncontext)
+ .unwrap(),
+ );
+ bytes
}
fn diffie_hellman(
@@ -178,7 +196,7 @@
use crypto_provider_test::p256::*;
#[apply(p256_test_cases)]
- fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh>) {
- testcase(PhantomData::<P256Ecdh>)
+ fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh>, _name: &str) {
+ testcase(PhantomData)
}
}
diff --git a/nearby/crypto/crypto_provider_openssl/src/x25519.rs b/nearby/crypto/crypto_provider_openssl/src/x25519.rs
index ff6f3b0..2cb4cab 100644
--- a/nearby/crypto/crypto_provider_openssl/src/x25519.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/x25519.rs
@@ -30,14 +30,15 @@
impl PublicKey<X25519> for X25519PublicKey {
type Error = ErrorStack;
+ type EncodedPublicKey = [u8; 32];
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
let key = PKey::public_key_from_raw_bytes(bytes, Id::X25519)?;
Ok(X25519PublicKey(key))
}
- fn to_bytes(&self) -> Vec<u8> {
- self.0.raw_public_key().unwrap()
+ fn to_bytes(&self) -> Self::EncodedPublicKey {
+ self.0.raw_public_key().unwrap().try_into().unwrap()
}
}
@@ -48,14 +49,15 @@
type Impl = X25519Ecdh;
type Error = ErrorStack;
type Rng = ();
+ type EncodedPublicKey = [u8; 32];
fn generate_random(_rng: &mut Self::Rng) -> Self {
let private_key = openssl::pkey::PKey::generate_x25519().unwrap();
Self(private_key)
}
- fn public_key_bytes(&self) -> Vec<u8> {
- self.0.raw_public_key().unwrap()
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
+ self.0.raw_public_key().unwrap().try_into().unwrap()
}
fn diffie_hellman(
diff --git a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
index e0bf534..a0638ff 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
+++ b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
@@ -6,15 +6,22 @@
[dependencies]
aead = "0.5.1"
-aes-gcm-siv = { version = "0.11.1", features = ["aes"] }
-crypto_provider.workspace = true
+aes-gcm-siv = { version = "0.11.1", features = [
+ "aes",
+], default-features = false }
+aes-gcm = { version = "0.10.3", features = [
+ "aes",
+], default-features = false }
+crypto_provider = { workspace = true }
hmac.workspace = true
hkdf.workspace = true
sha2.workspace = true
x25519-dalek.workspace = true
p256 = { workspace = true, features = ["ecdh"], default-features = false }
sec1.workspace = true
-ed25519-dalek = { workspace = true, default-features = false, features = ["rand_core"] }
+ed25519-dalek = { workspace = true, default-features = false, features = [
+ "rand_core",
+] }
rand = { workspace = true, default-features = false }
rand_core.workspace = true
subtle.workspace = true
@@ -31,5 +38,12 @@
[features]
default = ["alloc", "rand_chacha"]
-std = ["ed25519-dalek/default", "rand/std", "rand/std_rng", "crypto_provider/std", "crypto_provider/alloc"]
-alloc = ["aead/bytes"]
+std = [
+ "alloc",
+ "ed25519-dalek/default",
+ "rand/std",
+ "rand/std_rng",
+ "crypto_provider/std",
+ "crypto_provider/alloc",
+]
+alloc = ["aead/bytes", "aead/alloc", "cbc/alloc", "crypto_provider/alloc"]
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm.rs
new file mode 100644
index 0000000..f1d9e0f
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm.rs
@@ -0,0 +1,123 @@
+// 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 aead::Payload;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+
+// RustCrypto defined traits and types
+use aes::cipher::typenum::consts::{U12, U16};
+use aes::cipher::BlockCipher;
+use aes::cipher::BlockEncrypt;
+#[cfg(feature = "alloc")]
+use aes_gcm::aead::Aead as _;
+use aes_gcm::aead::KeyInit;
+use aes_gcm::AeadInPlace as _;
+
+// CryptoProvider traits and types
+use crypto_provider::aead::{Aead, AeadError, AeadInit};
+
+pub struct AesGcm<A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit>(
+ aes_gcm::AesGcm<A, U12>,
+);
+
+impl<A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit> crypto_provider::aead::AesGcm
+ for AesGcm<A>
+{
+}
+
+impl<K: crypto_provider::aes::AesKey, A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit>
+ AeadInit<K> for AesGcm<A>
+{
+ fn new(key: &K) -> Self {
+ Self(aes_gcm::AesGcm::<A, U12>::new(key.as_slice().into()))
+ }
+}
+
+impl<A: aes::cipher::BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit> Aead for AesGcm<A> {
+ const TAG_SIZE: usize = 16;
+ type Nonce = [u8; 12];
+ type Tag = [u8; 16];
+
+ #[cfg(feature = "alloc")]
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0
+ .encrypt(aes_gcm::Nonce::from_slice(nonce), Payload { msg, aad })
+ .map_err(|_| AeadError)
+ }
+
+ fn encrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
+ self.0
+ .encrypt_in_place_detached(aes_gcm::Nonce::from_slice(nonce), aad, msg)
+ .map(|arr| arr.into())
+ .map_err(|_| AeadError)
+ }
+
+ #[cfg(feature = "alloc")]
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0
+ .decrypt(aes_gcm::Nonce::from_slice(nonce), Payload { msg, aad })
+ .map_err(|_| AeadError)
+ }
+
+ fn decrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
+ self.0
+ .decrypt_in_place_detached(aes_gcm::Nonce::from_slice(nonce), aad, msg, tag.into())
+ .map_err(|_| AeadError)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use core::marker::PhantomData;
+
+ use crypto_provider_test::aead::aes_gcm::*;
+ use crypto_provider_test::aes::*;
+
+ use super::*;
+
+ #[apply(aes_128_gcm_test_cases)]
+ fn aes_gcm_128_test(testcase: CryptoProviderTestCase<AesGcm<aes::Aes128>>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_128_gcm_test_cases_detached)]
+ fn aes_128_gcm_test_detached(testcase: CryptoProviderTestCase<AesGcm<aes::Aes128>>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_gcm_test_cases)]
+ fn aes_gcm_256_test(testcase: CryptoProviderTestCase<AesGcm<aes::Aes256>>) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_gcm_test_cases_detached)]
+ fn aes_256_gcm_test_detached(testcase: CryptoProviderTestCase<AesGcm<aes::Aes256>>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm_siv.rs
index 402c2ed..408017f 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm_siv.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aead/aes_gcm_siv.rs
@@ -12,74 +12,118 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use aes_gcm_siv::{AeadInPlace, Aes128GcmSiv, Aes256GcmSiv, KeyInit, Nonce};
+#[cfg(feature = "alloc")]
extern crate alloc;
+#[cfg(feature = "alloc")]
+use aead::Payload;
+#[cfg(feature = "alloc")]
use alloc::vec::Vec;
-use crypto_provider::aead::{Aead, AeadError};
-use crypto_provider::aead::aes_gcm_siv::AesGcmSiv;
-use crypto_provider::aes::{Aes128Key, Aes256Key, AesKey};
+// RustCrypto defined traits and types
+use aes::cipher::typenum::consts::U16;
+use aes::cipher::BlockCipher;
+use aes::cipher::BlockEncrypt;
+#[cfg(feature = "alloc")]
+use aes_gcm_siv::aead::Aead as _;
+use aes_gcm_siv::aead::KeyInit;
+use aes_gcm_siv::AeadInPlace as _;
-pub struct AesGcmSiv128(Aes128GcmSiv);
+// CryptoProvider traits and types
+use crypto_provider::aead::{Aead, AeadError, AeadInit};
-impl AesGcmSiv for AesGcmSiv128 {}
+pub struct AesGcmSiv<A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit>(
+ aes_gcm_siv::AesGcmSiv<A>,
+);
-impl Aead for AesGcmSiv128 {
- const TAG_SIZE: usize = 16;
- type Nonce = [u8; 12];
- type Key = Aes128Key;
+impl<A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit> crypto_provider::aead::AesGcmSiv
+ for AesGcmSiv<A>
+{
+}
- fn new(key: &Self::Key) -> Self {
- Self(Aes128GcmSiv::new(key.as_slice().into()))
- }
-
- fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
- self.0.encrypt_in_place(Nonce::from_slice(nonce), aad, msg).map_err(|_| AeadError)
- }
-
- fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
- self.0.decrypt_in_place(Nonce::from_slice(nonce), aad, msg).map_err(|_| AeadError)
+impl<K: crypto_provider::aes::AesKey, A: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit>
+ AeadInit<K> for AesGcmSiv<A>
+{
+ fn new(key: &K) -> Self {
+ Self(aes_gcm_siv::AesGcmSiv::<A>::new(key.as_slice().into()))
}
}
-pub struct AesGcmSiv256(Aes256GcmSiv);
-
-impl AesGcmSiv for AesGcmSiv256 {}
-
-impl Aead for AesGcmSiv256 {
+impl<A: aes::cipher::BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit> Aead for AesGcmSiv<A> {
const TAG_SIZE: usize = 16;
type Nonce = [u8; 12];
- type Key = Aes256Key;
+ type Tag = [u8; 16];
- fn new(key: &Self::Key) -> Self {
- Self(Aes256GcmSiv::new(key.as_slice().into()))
+ #[cfg(feature = "alloc")]
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0
+ .encrypt(aes_gcm_siv::Nonce::from_slice(nonce), Payload { msg, aad })
+ .map_err(|_| AeadError)
}
- fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
- self.0.encrypt_in_place(Nonce::from_slice(nonce), aad, msg).map_err(|_| AeadError)
+ fn encrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
+ self.0
+ .encrypt_in_place_detached(aes_gcm_siv::Nonce::from_slice(nonce), aad, msg)
+ .map(|arr| arr.into())
+ .map_err(|_| AeadError)
}
- fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
- self.0.decrypt_in_place(Nonce::from_slice(nonce), aad, msg).map_err(|_| AeadError)
+ #[cfg(feature = "alloc")]
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError> {
+ self.0
+ .decrypt(aes_gcm_siv::Nonce::from_slice(nonce), Payload { msg, aad })
+ .map_err(|_| AeadError)
+ }
+
+ fn decrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
+ self.0
+ .decrypt_in_place_detached(aes_gcm_siv::Nonce::from_slice(nonce), aad, msg, tag.into())
+ .map_err(|_| AeadError)
}
}
#[cfg(test)]
mod tests {
use core::marker::PhantomData;
-
use crypto_provider_test::aead::aes_gcm_siv::*;
use crypto_provider_test::aes::*;
-
- use super::*;
+ use crypto_provider_test::prelude::apply;
#[apply(aes_128_gcm_siv_test_cases)]
- fn aes_gcm_siv_128_test(testcase: CryptoProviderTestCase<AesGcmSiv128>) {
+ fn aes_gcm_siv_128_test(
+ testcase: CryptoProviderTestCase<crate::aead::aes_gcm_siv::AesGcmSiv<aes::Aes128>>,
+ ) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_128_gcm_siv_test_cases_detached)]
+ fn aes_gcm_siv_128_test_detached(
+ testcase: CryptoProviderTestCase<crate::aead::aes_gcm_siv::AesGcmSiv<aes::Aes128>>,
+ ) {
testcase(PhantomData);
}
#[apply(aes_256_gcm_siv_test_cases)]
- fn aes_gcm_siv_256_test(testcase: CryptoProviderTestCase<AesGcmSiv256>) {
+ fn aes_gcm_siv_256_test(
+ testcase: CryptoProviderTestCase<crate::aead::aes_gcm_siv::AesGcmSiv<aes::Aes256>>,
+ ) {
+ testcase(PhantomData);
+ }
+
+ #[apply(aes_256_gcm_siv_test_cases_detached)]
+ fn aes_gcm_siv_256_test_detached(
+ testcase: CryptoProviderTestCase<crate::aead::aes_gcm_siv::AesGcmSiv<aes::Aes256>>,
+ ) {
testcase(PhantomData);
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aead/mod.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aead/mod.rs
index 7fc561b..e4c2c60 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/aead/mod.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aead/mod.rs
@@ -13,3 +13,5 @@
// limitations under the License.
pub(crate) mod aes_gcm_siv;
+
+pub(crate) mod aes_gcm;
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs
deleted file mode 100644
index 06d7224..0000000
--- a/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2022 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 aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
-use aes::Aes256;
-use alloc::vec::Vec;
-use crypto_provider::aes::{
- cbc::{AesCbcIv, DecryptionError},
- Aes256Key, AesKey,
-};
-
-/// RustCrypto implementation of AES-CBC with PKCS7 padding
-pub enum AesCbcPkcs7Padded {}
-impl crypto_provider::aes::cbc::AesCbcPkcs7Padded for AesCbcPkcs7Padded {
- fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8> {
- let encryptor = cbc::Encryptor::<Aes256>::new(key.as_array().into(), iv.into());
- encryptor.encrypt_padded_vec_mut::<Pkcs7>(message)
- }
-
- fn decrypt(
- key: &Aes256Key,
- iv: &AesCbcIv,
- ciphertext: &[u8],
- ) -> Result<Vec<u8>, DecryptionError> {
- cbc::Decryptor::<Aes256>::new(key.as_array().into(), iv.into())
- .decrypt_padded_vec_mut::<Pkcs7>(ciphertext)
- .map_err(|_| DecryptionError::BadPadding)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::AesCbcPkcs7Padded;
- use core::marker::PhantomData;
- use crypto_provider_test::aes::cbc::*;
-
- #[apply(aes_256_cbc_test_cases)]
- fn aes_256_cbc_test(testcase: CryptoProviderTestCase<AesCbcPkcs7Padded>) {
- testcase(PhantomData);
- }
-}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/cbc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/cbc.rs
new file mode 100644
index 0000000..c6d74f0
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/cbc.rs
@@ -0,0 +1,102 @@
+// Copyright 2022 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;
+
+use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
+use aes::Aes256;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+use crypto_provider::{
+ aes::{
+ cbc::{AesCbcIv, DecryptionError, EncryptionError},
+ Aes256Key, AesKey,
+ },
+ tinyvec::SliceVec,
+};
+
+/// RustCrypto implementation of AES-CBC with PKCS7 padding
+pub enum AesCbcPkcs7Padded {}
+impl crypto_provider::aes::cbc::AesCbcPkcs7Padded for AesCbcPkcs7Padded {
+ #[cfg(feature = "alloc")]
+ fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8> {
+ let encryptor = cbc::Encryptor::<Aes256>::new(key.as_array().into(), iv.into());
+ encryptor.encrypt_padded_vec_mut::<Pkcs7>(message)
+ }
+
+ fn encrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError> {
+ let encryptor = cbc::Encryptor::<Aes256>::new(key.as_array().into(), iv.into());
+ let message_len = message.len();
+ // Set the length so encrypt_padded_mut can write using the full capacity
+ // (Unlike `Vec.set_len`, `SliceVec.set_len` is safe and won't panic if len <= capacity)
+ message.set_len(message.capacity());
+ encryptor
+ .encrypt_padded_mut::<Pkcs7>(message, message_len)
+ .map(|result| result.len())
+ // `SliceVec.set_len` is safe, and won't panic because `encrypt_padded_mut` never
+ // returns a slice longer than the given buffer.
+ .map(|new_len| message.set_len(new_len))
+ .map_err(|_| {
+ message.set_len(message_len); // Set the buffer back to its original length
+ EncryptionError::PaddingFailed
+ })
+ }
+
+ #[cfg(feature = "alloc")]
+ fn decrypt(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &[u8],
+ ) -> Result<Vec<u8>, DecryptionError> {
+ cbc::Decryptor::<Aes256>::new(key.as_array().into(), iv.into())
+ .decrypt_padded_vec_mut::<Pkcs7>(ciphertext)
+ .map_err(|_| DecryptionError::BadPadding)
+ }
+
+ fn decrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError> {
+ // Decrypted size is always smaller than the input size because of padding, so we don't need
+ // to set the length to the full capacity.
+ cbc::Decryptor::<Aes256>::new(key.as_array().into(), iv.into())
+ .decrypt_padded_mut::<Pkcs7>(ciphertext)
+ .map(|result| result.len())
+ // `SliceVec.set_len` is safe, and won't panic because decrypted result length is always
+ // smaller than the input size.
+ .map(|new_len| ciphertext.set_len(new_len))
+ .map_err(|_| {
+ ciphertext.as_mut().fill(0);
+ DecryptionError::BadPadding
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::AesCbcPkcs7Padded;
+ use core::marker::PhantomData;
+ use crypto_provider_test::aes::cbc::*;
+
+ #[apply(aes_256_cbc_test_cases)]
+ fn aes_256_cbc_test(testcase: CryptoProviderTestCase<AesCbcPkcs7Padded>) {
+ testcase(PhantomData);
+ }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/ctr.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/ctr.rs
similarity index 88%
rename from nearby/crypto/crypto_provider_rustcrypto/src/aes/ctr.rs
rename to nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/ctr.rs
index 85cdac6..09ae557 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/aes/ctr.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/ctr.rs
@@ -33,11 +33,7 @@
}
}
- fn encrypt(&mut self, data: &mut [u8]) {
- self.cipher.apply_keystream(data);
- }
-
- fn decrypt(&mut self, data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
self.cipher.apply_keystream(data);
}
}
@@ -59,11 +55,7 @@
}
}
- fn encrypt(&mut self, data: &mut [u8]) {
- self.cipher.apply_keystream(data);
- }
-
- fn decrypt(&mut self, data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
self.cipher.apply_keystream(data);
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/mod.rs
similarity index 98%
rename from nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs
rename to nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/mod.rs
index c71f2ec..4c04bf5 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes_cp/mod.rs
@@ -22,7 +22,6 @@
};
/// Module implementing AES-CBC.
-#[cfg(feature = "alloc")]
pub(crate) mod cbc;
pub(crate) mod ctr;
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
index d11a5ea..ce8089e 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
@@ -15,8 +15,8 @@
use ed25519_dalek::Signer;
use crypto_provider::ed25519::{
- InvalidBytes, RawPrivateKey, RawPublicKey, RawSignature, Signature as _, SignatureError,
- PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH,
+ InvalidBytes, RawPrivateKey, RawPrivateKeyPermit, RawPublicKey, RawSignature, Signature as _,
+ SignatureError, PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH,
};
pub struct Ed25519;
@@ -33,11 +33,11 @@
type PublicKey = PublicKey;
type Signature = Signature;
- fn private_key(&self) -> [u8; PRIVATE_KEY_LENGTH] {
+ fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> [u8; PRIVATE_KEY_LENGTH] {
self.0.to_bytes()
}
- fn from_private_key(bytes: &RawPrivateKey) -> Self {
+ fn from_raw_private_key(bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self {
Self(ed25519_dalek::SigningKey::from_bytes(bytes))
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_cp.rs
similarity index 86%
rename from nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
rename to nearby/crypto/crypto_provider_rustcrypto/src/hkdf_cp.rs
index aba0d4a..48380fa 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_cp.rs
@@ -22,7 +22,7 @@
use hmac::digest::{HashMarker, OutputSizeUser};
/// RustCrypto based hkdf implementation
-pub struct Hkdf<D>
+pub struct Hkdf<D>(hkdf::Hkdf<D>)
where
D: OutputSizeUser,
D: CoreProxy,
@@ -33,10 +33,7 @@
+ Default
+ Clone,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
- Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
-{
- hkdf_impl: hkdf::Hkdf<D>,
-}
+ Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl<D> crypto_provider::hkdf::Hkdf for Hkdf<D>
where
@@ -52,7 +49,7 @@
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn new(salt: Option<&[u8]>, ikm: &[u8]) -> Self {
- Hkdf { hkdf_impl: hkdf::Hkdf::new(salt, ikm) }
+ Hkdf(hkdf::Hkdf::new(salt, ikm))
}
fn expand_multi_info(
@@ -60,11 +57,11 @@
info_components: &[&[u8]],
okm: &mut [u8],
) -> Result<(), InvalidLength> {
- self.hkdf_impl.expand_multi_info(info_components, okm).map_err(|_| InvalidLength)
+ self.0.expand_multi_info(info_components, okm).map_err(|_| InvalidLength)
}
fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
- self.hkdf_impl.expand(info, okm).map_err(|_| InvalidLength)
+ self.0.expand(info, okm).map_err(|_| InvalidLength)
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_cp.rs
similarity index 72%
rename from nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
rename to nearby/crypto/crypto_provider_rustcrypto/src/hmac_cp.rs
index dfda208..d8cef33 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_cp.rs
@@ -23,7 +23,7 @@
use hmac::Mac;
/// RustCrypto based hmac implementation
-pub struct Hmac<D>
+pub struct Hmac<D>(hmac::Hmac<D>)
where
D: OutputSizeUser,
D: CoreProxy,
@@ -34,43 +34,38 @@
+ Default
+ Clone,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
- Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
-{
- hmac_impl: hmac::Hmac<D>,
-}
+ Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl crypto_provider::hmac::Hmac<32> for Hmac<sha2::Sha256> {
#[allow(clippy::expect_used)]
fn new_from_key(key: [u8; 32]) -> Self {
hmac::Hmac::new_from_slice(&key)
- .map(|hmac| Self { hmac_impl: hmac })
+ .map(Self)
.expect("length will always be valid because input key is of fixed size")
}
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
- hmac::Hmac::new_from_slice(key)
- .map(|hmac| Self { hmac_impl: hmac })
- .map_err(|_| InvalidLength)
+ hmac::Hmac::new_from_slice(key).map(Self).map_err(|_| InvalidLength)
}
fn update(&mut self, data: &[u8]) {
- self.hmac_impl.update(data);
+ self.0.update(data);
}
fn finalize(self) -> [u8; 32] {
- self.hmac_impl.finalize().into_bytes().into()
+ self.0.finalize().into_bytes().into()
}
fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
- self.hmac_impl.verify_slice(tag).map_err(|_| MacError)
+ self.0.verify_slice(tag).map_err(|_| MacError)
}
fn verify(self, tag: [u8; 32]) -> Result<(), MacError> {
- self.hmac_impl.verify(&tag.into()).map_err(|_| MacError)
+ self.0.verify(&tag.into()).map_err(|_| MacError)
}
fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
- self.hmac_impl.verify_truncated_left(tag).map_err(|_| MacError)
+ self.0.verify_truncated_left(tag).map_err(|_| MacError)
}
}
@@ -78,34 +73,32 @@
#[allow(clippy::expect_used)]
fn new_from_key(key: [u8; 64]) -> Self {
hmac::Hmac::new_from_slice(&key)
- .map(|hmac| Self { hmac_impl: hmac })
+ .map(Self)
.expect("length will always be valid because input key is of fixed size")
}
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
- hmac::Hmac::new_from_slice(key)
- .map(|hmac| Self { hmac_impl: hmac })
- .map_err(|_| InvalidLength)
+ hmac::Hmac::new_from_slice(key).map(Self).map_err(|_| InvalidLength)
}
fn update(&mut self, data: &[u8]) {
- self.hmac_impl.update(data);
+ self.0.update(data);
}
fn finalize(self) -> [u8; 64] {
- self.hmac_impl.finalize().into_bytes().into()
+ self.0.finalize().into_bytes().into()
}
fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
- self.hmac_impl.verify_slice(tag).map_err(|_| MacError)
+ self.0.verify_slice(tag).map_err(|_| MacError)
}
fn verify(self, tag: [u8; 64]) -> Result<(), MacError> {
- self.hmac_impl.verify(&tag.into()).map_err(|_| MacError)
+ self.0.verify(&tag.into()).map_err(|_| MacError)
}
fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
- self.hmac_impl.verify_truncated_left(tag).map_err(|_| MacError)
+ self.0.verify_truncated_left(tag).map_err(|_| MacError)
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
index e95712c..628f679 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
@@ -25,6 +25,7 @@
use core::{fmt::Debug, marker::PhantomData};
+pub use aes;
use cfg_if::cfg_if;
pub use hkdf;
pub use hmac;
@@ -35,17 +36,17 @@
/// Contains the RustCrypto backed impls for AES-GCM-SIV operations
mod aead;
/// Contains the RustCrypto backed AES impl for CryptoProvider
-pub mod aes;
+pub mod aes_cp;
/// Contains the RustCrypto backed impl for ed25519 key generation, signing, and verification
mod ed25519;
/// Contains the RustCrypto backed hkdf impl for CryptoProvider
-mod hkdf_rc;
+mod hkdf_cp;
/// Contains the RustCrypto backed hmac impl for CryptoProvider
-mod hmac_rc;
+mod hmac_cp;
/// Contains the RustCrypto backed P256 impl for CryptoProvider
mod p256;
/// Contains the RustCrypto backed SHA2 impl for CryptoProvider
-mod sha2_rc;
+mod sha2_cp;
/// Contains the RustCrypto backed X25519 impl for CryptoProvider
mod x25519;
@@ -54,9 +55,11 @@
/// Providing a type alias for compatibility with existing usage of RustCrypto
/// by default we use StdRng for the underlying csprng
pub type RustCrypto = RustCryptoImpl<rand::rngs::StdRng>;
- } else {
+ } else if #[cfg(feature = "rand_chacha")] {
/// A no_std compatible implementation of CryptoProvider backed by RustCrypto crates
pub type RustCrypto = RustCryptoImpl<rand_chacha::ChaCha20Rng>;
+ } else {
+ compile_error!("Must specify either --features std or --features rand_chacha");
}
}
@@ -76,23 +79,24 @@
impl<R: CryptoRng + SeedableRng + RngCore + Eq + PartialEq + Debug + Clone + Send>
crypto_provider::CryptoProvider for RustCryptoImpl<R>
{
- type HkdfSha256 = hkdf_rc::Hkdf<sha2::Sha256>;
- type HmacSha256 = hmac_rc::Hmac<sha2::Sha256>;
- type HkdfSha512 = hkdf_rc::Hkdf<sha2::Sha512>;
- type HmacSha512 = hmac_rc::Hmac<sha2::Sha512>;
- #[cfg(feature = "alloc")]
- type AesCbcPkcs7Padded = aes::cbc::AesCbcPkcs7Padded;
+ type HkdfSha256 = hkdf_cp::Hkdf<sha2::Sha256>;
+ type HmacSha256 = hmac_cp::Hmac<sha2::Sha256>;
+ type HkdfSha512 = hkdf_cp::Hkdf<sha2::Sha512>;
+ type HmacSha512 = hmac_cp::Hmac<sha2::Sha512>;
+ type AesCbcPkcs7Padded = aes_cp::cbc::AesCbcPkcs7Padded;
type X25519 = x25519::X25519Ecdh<R>;
type P256 = p256::P256Ecdh<R>;
- type Sha256 = sha2_rc::RustCryptoSha256;
- type Sha512 = sha2_rc::RustCryptoSha512;
- type Aes128 = aes::Aes128;
- type Aes256 = aes::Aes256;
- type AesCtr128 = aes::ctr::AesCtr128;
- type AesCtr256 = aes::ctr::AesCtr256;
+ type Sha256 = sha2_cp::RustCryptoSha256;
+ type Sha512 = sha2_cp::RustCryptoSha512;
+ type Aes128 = aes_cp::Aes128;
+ type Aes256 = aes_cp::Aes256;
+ type AesCtr128 = aes_cp::ctr::AesCtr128;
+ type AesCtr256 = aes_cp::ctr::AesCtr256;
type Ed25519 = ed25519::Ed25519;
- type Aes128GcmSiv = aead::aes_gcm_siv::AesGcmSiv128;
- type Aes256GcmSiv = aead::aes_gcm_siv::AesGcmSiv256;
+ type Aes128GcmSiv = aead::aes_gcm_siv::AesGcmSiv<aes::Aes128>;
+ type Aes256GcmSiv = aead::aes_gcm_siv::AesGcmSiv<aes::Aes256>;
+ type Aes128Gcm = aead::aes_gcm::AesGcm<aes::Aes128>;
+ type Aes256Gcm = aead::aes_gcm::AesGcm<aes::Aes256>;
type CryptoRng = RcRng<R>;
fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
@@ -124,6 +128,7 @@
mod tests {
use core::marker::PhantomData;
+ use crypto_provider_test::prelude::*;
use crypto_provider_test::sha2::*;
use crate::RustCrypto;
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs b/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs
index 539ccc0..98a6cd4 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs
@@ -12,14 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate alloc;
-
use crate::RcRng;
-use alloc::vec::Vec;
use core::marker::PhantomData;
use crypto_provider::{
elliptic_curve::{EcdhProvider, EphemeralSecret},
- p256::P256,
+ p256::{PointCompression, P256},
+ tinyvec::ArrayVec,
};
use p256::{
elliptic_curve,
@@ -52,8 +50,12 @@
p256::PublicKey::from_sec1_bytes(bytes).map(Self)
}
- fn to_sec1_bytes(&self) -> Vec<u8> {
- self.0.to_encoded_point(true).as_bytes().to_vec()
+ fn to_sec1_bytes(&self, point_compression: PointCompression) -> ArrayVec<[u8; 65]> {
+ let mut bytes = ArrayVec::<[u8; 65]>::new();
+ bytes.extend_from_slice(
+ self.0.to_encoded_point(point_compression == PointCompression::Compressed).as_bytes(),
+ );
+ bytes
}
#[allow(clippy::expect_used)]
@@ -87,6 +89,7 @@
type Impl = P256Ecdh<R>;
type Error = sec1::Error;
type Rng = RcRng<R>;
+ type EncodedPublicKey = ArrayVec<[u8; 65]>;
fn generate_random(rng: &mut Self::Rng) -> Self {
Self {
@@ -95,8 +98,10 @@
}
}
- fn public_key_bytes(&self) -> Vec<u8> {
- self.secret.public_key().to_encoded_point(false).as_bytes().into()
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
+ let mut bytes = Self::EncodedPublicKey::new();
+ bytes.extend_from_slice(self.secret.public_key().to_encoded_point(false).as_bytes());
+ bytes
}
fn diffie_hellman(
@@ -136,7 +141,7 @@
use rand::rngs::StdRng;
#[apply(p256_test_cases)]
- fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh<StdRng>>) {
+ fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh<StdRng>>, _name: &str) {
testcase(PhantomData::<P256Ecdh<StdRng>>)
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/sha2_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/sha2_cp.rs
similarity index 100%
rename from nearby/crypto/crypto_provider_rustcrypto/src/sha2_rc.rs
rename to nearby/crypto/crypto_provider_rustcrypto/src/sha2_cp.rs
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
index 445e858..ad67777 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
@@ -12,10 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate alloc;
-
use crate::RcRng;
-use alloc::vec::Vec;
use core::marker::PhantomData;
use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey};
use crypto_provider::x25519::X25519;
@@ -45,6 +42,7 @@
type Impl = X25519Ecdh<R>;
type Error = Error;
type Rng = RcRng<R>;
+ type EncodedPublicKey = [u8; 32];
fn generate_random(rng: &mut Self::Rng) -> Self {
Self {
@@ -53,9 +51,9 @@
}
}
- fn public_key_bytes(&self) -> Vec<u8> {
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
let pubkey: x25519_dalek::PublicKey = (&self.secret).into();
- pubkey.to_bytes().into()
+ pubkey.to_bytes()
}
fn diffie_hellman(
@@ -90,14 +88,15 @@
impl PublicKey<X25519> for X25519PublicKey {
type Error = Error;
+ type EncodedPublicKey = [u8; 32];
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
let byte_sized: [u8; 32] = bytes.try_into().map_err(|_| Error::WrongSize)?;
Ok(Self(byte_sized.into()))
}
- fn to_bytes(&self) -> Vec<u8> {
- self.0.as_bytes().to_vec()
+ fn to_bytes(&self) -> Self::EncodedPublicKey {
+ self.0.to_bytes()
}
}
diff --git a/nearby/crypto/crypto_provider_stubs/Cargo.toml b/nearby/crypto/crypto_provider_stubs/Cargo.toml
index d7c4d45..4e8bdec 100644
--- a/nearby/crypto/crypto_provider_stubs/Cargo.toml
+++ b/nearby/crypto/crypto_provider_stubs/Cargo.toml
@@ -5,4 +5,4 @@
publish.workspace = true
[dependencies]
-crypto_provider = {workspace = true, features = ["std", "alloc"] }
\ No newline at end of file
+crypto_provider = {workspace = true, features = ["std", "alloc"] }
diff --git a/nearby/crypto/crypto_provider_stubs/src/lib.rs b/nearby/crypto/crypto_provider_stubs/src/lib.rs
index 5d54b72..32c9381 100644
--- a/nearby/crypto/crypto_provider_stubs/src/lib.rs
+++ b/nearby/crypto/crypto_provider_stubs/src/lib.rs
@@ -20,21 +20,23 @@
use std::fmt::Debug;
-use crypto_provider::ed25519::{RawPrivateKey, RawPublicKey, RawSignature};
+use crypto_provider::aead::AeadInit;
use crypto_provider::{
- aead::aes_gcm_siv::AesGcmSiv,
- aead::{Aead, AeadError},
+ aead::{Aead, AeadError, AesGcm, AesGcmSiv},
aes::{
- cbc::{AesCbcIv, AesCbcPkcs7Padded, DecryptionError},
+ cbc::{AesCbcIv, AesCbcPkcs7Padded, DecryptionError, EncryptionError},
ctr::{AesCtr, NonceAndCounter},
Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher,
},
- ed25519,
- ed25519::{Ed25519Provider, InvalidBytes, KeyPair, Signature, SignatureError},
+ ed25519::{
+ self, Ed25519Provider, InvalidBytes, KeyPair, RawPrivateKey, RawPrivateKeyPermit,
+ RawPublicKey, RawSignature, Signature, SignatureError,
+ },
elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey},
hkdf::{Hkdf, InvalidLength},
hmac::{Hmac, MacError},
- p256::{P256PublicKey, P256},
+ p256::{P256PublicKey, PointCompression, P256},
+ tinyvec::{ArrayVec, SliceVec},
x25519::X25519,
};
@@ -58,6 +60,8 @@
type Ed25519 = Ed25519Stubs;
type Aes128GcmSiv = Aes128Stubs;
type Aes256GcmSiv = Aes256Stubs;
+ type Aes128Gcm = Aes128Stubs;
+ type Aes256Gcm = Aes256Stubs;
type CryptoRng = ();
fn constant_time_eq(_a: &[u8], _b: &[u8]) -> bool {
@@ -171,6 +175,14 @@
unimplemented!()
}
+ fn encrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ message: &mut SliceVec<u8>,
+ ) -> Result<(), EncryptionError> {
+ unimplemented!()
+ }
+
fn decrypt(
_key: &Aes256Key,
_iv: &AesCbcIv,
@@ -178,6 +190,14 @@
) -> Result<Vec<u8>, DecryptionError> {
unimplemented!()
}
+
+ fn decrypt_in_place(
+ key: &Aes256Key,
+ iv: &AesCbcIv,
+ ciphertext: &mut SliceVec<u8>,
+ ) -> Result<(), DecryptionError> {
+ unimplemented!()
+ }
}
pub struct X25519Stubs;
@@ -194,12 +214,13 @@
type Impl = X25519Stubs;
type Error = ();
type Rng = ();
+ type EncodedPublicKey = [u8; 32];
fn generate_random(_rng: &mut Self::Rng) -> Self {
unimplemented!()
}
- fn public_key_bytes(&self) -> Vec<u8> {
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
unimplemented!()
}
@@ -215,12 +236,13 @@
type Impl = P256Stubs;
type Error = ();
type Rng = ();
+ type EncodedPublicKey = ArrayVec<[u8; 65]>;
fn generate_random(_rng: &mut Self::Rng) -> Self {
unimplemented!()
}
- fn public_key_bytes(&self) -> Vec<u8> {
+ fn public_key_bytes(&self) -> Self::EncodedPublicKey {
unimplemented!()
}
@@ -237,12 +259,13 @@
impl PublicKey<X25519> for EcdhPubKey {
type Error = ();
+ type EncodedPublicKey = [u8; 32];
fn from_bytes(_bytes: &[u8]) -> Result<Self, Self::Error> {
unimplemented!()
}
- fn to_bytes(&self) -> Vec<u8> {
+ fn to_bytes(&self) -> Self::EncodedPublicKey {
unimplemented!()
}
}
@@ -257,7 +280,7 @@
unimplemented!()
}
- fn to_sec1_bytes(&self) -> Vec<u8> {
+ fn to_sec1_bytes(&self, _point_compression: PointCompression) -> ArrayVec<[u8; 65]> {
unimplemented!()
}
@@ -294,6 +317,12 @@
pub struct Aes128Stubs;
+impl AeadInit<Aes128Key> for Aes128Stubs {
+ fn new(key: &Aes128Key) -> Self {
+ unimplemented!()
+ }
+}
+
impl AesCipher for Aes128Stubs {
type Key = Aes128Key;
@@ -321,11 +350,7 @@
unimplemented!()
}
- fn encrypt(&mut self, _data: &mut [u8]) {
- unimplemented!()
- }
-
- fn decrypt(&mut self, _data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
unimplemented!()
}
}
@@ -333,25 +358,48 @@
impl Aead for Aes128Stubs {
const TAG_SIZE: usize = 16;
type Nonce = [u8; 12];
- type Key = Aes128Key;
+ type Tag = [u8; 16];
- fn new(key: &Self::Key) -> Self {
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
unimplemented!()
}
- fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
+ fn encrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
unimplemented!()
}
- fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
+ unimplemented!()
+ }
+
+ fn decrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
unimplemented!()
}
}
impl AesGcmSiv for Aes128Stubs {}
+impl AesGcm for Aes128Stubs {}
+
pub struct Aes256Stubs;
+impl AeadInit<Aes256Key> for Aes256Stubs {
+ fn new(key: &Aes256Key) -> Self {
+ unimplemented!()
+ }
+}
+
impl AesCipher for Aes256Stubs {
type Key = Aes256Key;
@@ -379,11 +427,7 @@
unimplemented!()
}
- fn encrypt(&mut self, _data: &mut [u8]) {
- unimplemented!()
- }
-
- fn decrypt(&mut self, _data: &mut [u8]) {
+ fn apply_keystream(&mut self, data: &mut [u8]) {
unimplemented!()
}
}
@@ -391,23 +435,40 @@
impl Aead for Aes256Stubs {
const TAG_SIZE: usize = 16;
type Nonce = [u8; 12];
- type Key = Aes256Key;
+ type Tag = [u8; 16];
- fn new(key: &Self::Key) -> Self {
+ fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
unimplemented!()
}
- fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
+ fn encrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ ) -> Result<Self::Tag, AeadError> {
unimplemented!()
}
- fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &[u8; 12]) -> Result<(), AeadError> {
+ fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
+ unimplemented!()
+ }
+
+ fn decrypt_detached(
+ &self,
+ msg: &mut [u8],
+ aad: &[u8],
+ nonce: &Self::Nonce,
+ tag: &Self::Tag,
+ ) -> Result<(), AeadError> {
unimplemented!()
}
}
impl AesGcmSiv for Aes256Stubs {}
+impl AesGcm for Aes256Stubs {}
+
pub struct Ed25519Stubs;
impl Ed25519Provider for Ed25519Stubs {
@@ -457,11 +518,11 @@
type PublicKey = PublicKeyStubs;
type Signature = SignatureStubs;
- fn private_key(&self) -> RawPrivateKey {
+ fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey {
unimplemented!()
}
- fn from_private_key(_bytes: &RawPrivateKey) -> Self
+ fn from_raw_private_key(_bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self
where
Self: Sized,
{
diff --git a/nearby/crypto/crypto_provider_test/Cargo.toml b/nearby/crypto/crypto_provider_test/Cargo.toml
index a4d92ec..4064330 100644
--- a/nearby/crypto/crypto_provider_test/Cargo.toml
+++ b/nearby/crypto/crypto_provider_test/Cargo.toml
@@ -5,7 +5,7 @@
publish.workspace = true
[dependencies]
-crypto_provider = { workspace = true, features = ["test_vectors"] }
+crypto_provider = { workspace = true, features = ["raw_private_key_permit", "test_vectors", "alloc"] }
rand_ext.workspace = true
test_helper.workspace = true
@@ -14,4 +14,4 @@
rstest.workspace = true
rstest_reuse.workspace = true
wycheproof.workspace = true
-hex.workspace = true
\ No newline at end of file
+hex.workspace = true
diff --git a/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock b/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock
index 9e1d140..bd8f6f9 100644
--- a/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock
+++ b/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock
@@ -25,6 +25,20 @@
]
[[package]]
+name = "aes-gcm"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
+[[package]]
name = "aes-gcm-siv"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -165,6 +179,9 @@
[[package]]
name = "crypto_provider"
version = "0.1.0"
+dependencies = [
+ "tinyvec",
+]
[[package]]
name = "crypto_provider_default"
@@ -193,6 +210,7 @@
dependencies = [
"aead",
"aes",
+ "aes-gcm",
"aes-gcm-siv",
"cbc",
"cfg-if",
@@ -239,9 +257,9 @@
[[package]]
name = "curve25519-dalek"
-version = "4.0.0-rc.3"
+version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7"
+checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -307,9 +325,9 @@
[[package]]
name = "ed25519-dalek"
-version = "2.0.0-rc.3"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faa8e9049d5d72bfc12acbc05914731b5322f79b5e2f195e9f2d705fca22ab4c"
+checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"
dependencies = [
"curve25519-dalek",
"ed25519",
@@ -390,6 +408,16 @@
]
[[package]]
+name = "ghash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
+[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -732,6 +760,12 @@
]
[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+
+[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -773,9 +807,9 @@
[[package]]
name = "x25519-dalek"
-version = "2.0.0-rc.3"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a"
+checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96"
dependencies = [
"curve25519-dalek",
"rand_core",
diff --git a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs
new file mode 100644
index 0000000..88eaf32
--- /dev/null
+++ b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs
@@ -0,0 +1,316 @@
+// 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.
+use alloc::vec::Vec;
+use core::marker;
+
+use hex_literal::hex;
+use rstest_reuse::template;
+
+pub use crate::prelude;
+use crypto_provider::aead::{AeadInit, AesGcm};
+
+/// Test AES-GCM-128 encryption
+pub fn aes_128_gcm_test_encrypt<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC4
+ let test_key = hex!("bedcfb5a011ebc84600fcb296c15af0d");
+ let nonce = hex!("438a547a94ea88dce46c6c85");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("");
+ let tag = hex!("960247ba5cde02e41a313c4c0136edc3");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("Should succeed");
+ assert_eq!(&result[..], &tag);
+}
+
+pub fn aes_128_gcm_test_encrypt_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC4
+ let test_key = hex!("bedcfb5a011ebc84600fcb296c15af0d");
+ let nonce = hex!("438a547a94ea88dce46c6c85");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("");
+ let tag = hex!("960247ba5cde02e41a313c4c0136edc3");
+ let mut buf = Vec::from(msg.as_slice());
+ let actual_tag: [u8; 16] = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &[0_u8; 0]);
+ assert_eq!(&actual_tag, &tag);
+}
+
+/// Test AES-GCM-128 decryption
+pub fn aes_128_gcm_test_decrypt<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC2
+ let test_key = hex!("5b9604fe14eadba931b0ccf34843dab9");
+ let nonce = hex!("921d2507fa8007b7bd067d34");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("001d0c231287c1182784554ca3a21908");
+ let ct = hex!("49d8b9783e911913d87094d1f63cc765");
+ let ad = hex!("00112233445566778899aabbccddeeff");
+ let tag = hex!("1e348ba07cca2cf04c618cb4d43a5b92");
+ let result = aes.encrypt(&msg, &ad, &nonce).expect("should succeed");
+ assert_eq!(&result[..16], &ct);
+ assert_eq!(&result[16..], &tag);
+ assert_eq!(A::TAG_SIZE, result[16..].len());
+ let result = aes.decrypt(&result[..], &ad, &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-GCM-128 decryption
+pub fn aes_128_gcm_test_decrypt_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC2
+ let test_key = hex!("5b9604fe14eadba931b0ccf34843dab9");
+ let nonce = hex!("921d2507fa8007b7bd067d34");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("001d0c231287c1182784554ca3a21908");
+ let ct = hex!("49d8b9783e911913d87094d1f63cc765");
+ let ad = hex!("00112233445566778899aabbccddeeff");
+ let tag = hex!("1e348ba07cca2cf04c618cb4d43a5b92");
+ let mut buf = Vec::from(msg.as_slice());
+ let actual_tag = aes.encrypt_detached(&mut buf, &ad, &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(actual_tag, tag);
+ assert!(aes.decrypt_detached(&mut buf, &ad, &nonce, &tag).is_ok());
+ assert_eq!(&buf[..], &msg);
+}
+
+/// Test AES-GCM-128 decryption
+pub fn aes_128_gcm_test_decrypt_detached_bad_tag<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC23
+ let test_key = hex!("000102030405060708090a0b0c0d0e0f");
+ let nonce = hex!("505152535455565758595a5b");
+ let aes = A::new(&test_key.into());
+ let ct = hex!("eb156d081ed6b6b55f4612f021d87b39");
+ let mut buf = Vec::from(ct.as_slice());
+ let bad_tag = hex!("d9847dbc326a06e988c77ad3863e6083");
+ aes.decrypt_detached(&mut buf, b"", &nonce, &bad_tag)
+ .expect_err("decryption tag verification should fail");
+ // assert that the buffer does not change if tag verification fails
+ assert_eq!(buf, ct);
+}
+
+/// Test AES-256-GCM encryption/decryption
+pub fn aes_256_gcm_test_tc74<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC74
+ let test_key = hex!("29d3a44f8723dc640239100c365423a312934ac80239212ac3df3421a2098123");
+ let nonce = hex!("00112233445566778899aabb");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("");
+ let ad = hex!("aabbccddeeff");
+ let tag = hex!("2a7d77fa526b8250cb296078926b5020");
+ let result = aes.encrypt(&msg, &ad, &nonce).expect("should succeed");
+ assert_eq!(&result[..], &tag);
+ assert_eq!(A::TAG_SIZE, result.len());
+ let result = aes.decrypt(&result, &ad, &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-256-GCM encryption/decryption
+pub fn aes_256_gcm_test_tc74_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC74
+ let test_key = hex!("29d3a44f8723dc640239100c365423a312934ac80239212ac3df3421a2098123");
+ let nonce = hex!("00112233445566778899aabb");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("");
+ let ad = hex!("aabbccddeeff");
+ let ct = hex!("");
+ let tag = hex!("2a7d77fa526b8250cb296078926b5020");
+ let mut buf = Vec::new();
+ buf.extend_from_slice(&msg);
+ let actual_tag = aes.encrypt_detached(&mut buf, &ad, &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(&actual_tag, &tag);
+ assert_eq!(A::TAG_SIZE, tag.len());
+ assert!(aes.decrypt_detached(&mut buf, &ad, &nonce, &actual_tag).is_ok());
+ assert_eq!(&buf, &msg);
+}
+
+/// Test AES-256-GCM encryption/decryption
+pub fn aes_256_gcm_test_tc79<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC79
+ let test_key = hex!("59d4eafb4de0cfc7d3db99a8f54b15d7b39f0acc8da69763b019c1699f87674a");
+ let nonce = hex!("2fcb1b38a99e71b84740ad9b");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("549b365af913f3b081131ccb6b825588");
+ let ct = hex!("f58c16690122d75356907fd96b570fca");
+ let tag = hex!("28752c20153092818faba2a334640d6e");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..16], &ct);
+ assert_eq!(&result[16..], &tag);
+ let result = aes.decrypt(&result[..], b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-256-GCM encryption/decryption
+pub fn aes_256_gcm_test_tc79_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC79
+ let test_key = hex!("59d4eafb4de0cfc7d3db99a8f54b15d7b39f0acc8da69763b019c1699f87674a");
+ let nonce = hex!("2fcb1b38a99e71b84740ad9b");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("549b365af913f3b081131ccb6b825588");
+ let ct = hex!("f58c16690122d75356907fd96b570fca");
+ let tag = hex!("28752c20153092818faba2a334640d6e");
+ let mut buf = Vec::from(msg.as_slice());
+ let actual_tag = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(&actual_tag, &tag);
+ assert!(aes.decrypt_detached(&mut buf, b"", &nonce, &tag).is_ok());
+ assert_eq!(&buf, &msg);
+}
+
+/// Test AES-256-GCM encryption/decryption where the tag given to decryption doesn't match.
+pub fn aes_256_gcm_test_decrypt_detached_bad_tag<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcm<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
+ // TC94
+ let test_key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+ let nonce = hex!("505152535455565758595a5b");
+ let aes = A::new(&test_key.into());
+ let aad = hex!("");
+ let ct = hex!("b2061457c0759fc1749f174ee1ccadfa");
+ let bad_tag = hex!("9de8fef6d8ab1bf1bf887232eab590dd");
+ let mut buf = Vec::from(ct.as_slice());
+ aes.decrypt_detached(&mut buf, &aad, &nonce, &bad_tag)
+ .expect_err("Decrypting with bad tag should fail");
+ // assert that the buffer does not change if tag verification fails
+ assert_eq!(buf, ct);
+}
+
+/// Generates the test cases to validate the AES-128-GCM implementation.
+/// For example, to test `MyAesGcm128Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_128_gcm_test_cases)]
+/// fn aes_128_gcm_tests(testcase: CryptoProviderTestCase<MyAesGcmImpl>) {
+/// testcase(MyAesGcm128Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::encrypt(aes_128_gcm_test_encrypt)]
+#[case::decrypt(aes_128_gcm_test_decrypt)]
+fn aes_128_gcm_test_cases<F: AesGcmFactory<Key = Aes128Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
+
+/// Generates the test cases to validate the AES-128-GCM implementation.
+/// For example, to test `MyAesGcm128Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_128_gcm_test_cases_detached)]
+/// fn aes_128_gcm_tests(testcase: CryptoProviderTestCase<MyAesGcmImpl>) {
+/// testcase(MyAesGcm128Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::encrypt_detached(aes_128_gcm_test_encrypt_detached)]
+#[case::decrypt_detached(aes_128_gcm_test_decrypt_detached)]
+#[case::decrypt_detached_bad_tag(aes_128_gcm_test_decrypt_detached_bad_tag)]
+fn aes_128_gcm_test_cases_detached<F: AesGcmFactory<Key = Aes128Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
+
+/// Generates the test cases to validate the AES-256-GCM implementation.
+/// For example, to test `MyAesGcm256Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_256_gcm_test_cases)]
+/// fn aes_256_gcm_tests(testcase: CryptoProviderTestCase<MyAesGcm256Impl>) {
+/// testcase(MyAesGcm256Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::tc74(aes_256_gcm_test_tc74)]
+#[case::tc79(aes_256_gcm_test_tc79)]
+fn aes_256_gcm_test_cases<F: AesGcmFactory<Key = Aes256Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
+
+/// Generates the test cases to validate the AES-256-GCM implementation.
+/// For example, to test `MyAesGcm256Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_256_gcm_test_cases_detached)]
+/// fn aes_256_gcm_tests(testcase: CryptoProviderTestCase<MyAesGcm256Impl>) {
+/// testcase(MyAesGcm256Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::tc74_detached(aes_256_gcm_test_tc74_detached)]
+#[case::tc79_detached(aes_256_gcm_test_tc79_detached)]
+#[case::decrypt_detached_bad_tag(aes_256_gcm_test_decrypt_detached_bad_tag)]
+fn aes_256_gcm_test_cases_detached<F: AesGcmFactory<Key = Aes256Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
diff --git a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs
index 893fba2..56d2215 100644
--- a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs
+++ b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs
@@ -18,12 +18,28 @@
use rstest_reuse::template;
pub use crate::prelude;
-use crypto_provider::aes::{Aes128Key, Aes256Key};
+use crypto_provider::aead::{AeadInit, AesGcmSiv};
-use crypto_provider::aead::aes_gcm_siv::AesGcmSiv;
+/// Test AES-GCM-SIV-128 encryption
+pub fn aes_128_gcm_siv_test_encrypt<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC1
+ let test_key = hex!("01000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("");
+ let tag = hex!("dc20e2d83f25705bb49e439eca56de25");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("Should succeed");
+ assert_eq!(&result[..], &tag);
+}
-/// Test AES-GCM-SIV-128 encryption/decryption
-pub fn aes_128_gcm_siv_test<A: AesGcmSiv<Key = Aes128Key>>(_marker: marker::PhantomData<A>) {
+pub fn aes_128_gcm_siv_test_encrypt_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
// https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
// TC1
let test_key = hex!("01000000000000000000000000000000");
@@ -32,23 +48,102 @@
let msg = hex!("");
let mut buf = Vec::from(msg.as_slice());
let tag = hex!("dc20e2d83f25705bb49e439eca56de25");
- assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..], &tag);
+ let actual_tag: [u8; 16] = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &[0_u8; 0]);
+ assert_eq!(&actual_tag, &tag);
+}
+
+/// Test AES-GCM-SIV-128 decryption
+pub fn aes_128_gcm_siv_test_decrypt<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
// TC2
+ let test_key = hex!("01000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("0100000000000000");
+ let ct = hex!("b5d839330ac7b786");
+ let tag = hex!("578782fff6013b815b287c22493a364c");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..8], &ct);
+ assert_eq!(&result[8..], &tag);
+ assert_eq!(A::TAG_SIZE, result[8..].len());
+ let result = aes.decrypt(&result[..], b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-GCM-SIV-128 decryption
+pub fn aes_128_gcm_siv_test_decrypt_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC2
+ let test_key = hex!("01000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
let msg = hex!("0100000000000000");
let ct = hex!("b5d839330ac7b786");
let tag = hex!("578782fff6013b815b287c22493a364c");
let mut buf = Vec::from(msg.as_slice());
- assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..8], &ct);
- assert_eq!(&buf[8..], &tag);
- assert_eq!(A::TAG_SIZE, buf[8..].len());
- assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok());
+ let actual_tag = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(actual_tag, tag);
+ assert!(aes.decrypt_detached(&mut buf, b"", &nonce, &tag).is_ok());
assert_eq!(&buf[..], &msg);
}
+/// Test AES-GCM-SIV-128 decryption where the tag given to decryption doesn't match
+pub fn aes_128_gcm_siv_test_decrypt_detached_bad_tag<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes128Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC45
+ let test_key = hex!("00112233445566778899aabbccddeeff");
+ let nonce = hex!("000000000000000000000000");
+ let aad = hex!("9ea3371e258288d5a01b15384e2c99ee");
+ let aes = A::new(&test_key.into());
+ // Use a longer ciphertext as the test case to make sure it's not unchanged only for the most
+ // recent block.
+ let ct = hex!(
+ "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
+ "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
+ );
+ let bad_tag = hex!("13a1883272188b4c8d2727178198fe95");
+ let mut buf = Vec::from(ct.as_slice());
+ aes.decrypt_detached(&mut buf, &aad, &nonce, &bad_tag).expect_err("Decryption should fail");
+ assert_eq!(&buf, &ct); // Buffer should be unchanged if decryption failed
+}
+
/// Test AES-256-GCM-SIV encryption/decryption
-pub fn aes_256_gcm_siv_test<A: AesGcmSiv<Key = Aes256Key>>(_marker: marker::PhantomData<A>) {
+pub fn aes_256_gcm_siv_test_tc77<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC77
+ let test_key = hex!("0100000000000000000000000000000000000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("0100000000000000");
+ let ct = hex!("c2ef328e5c71c83b");
+ let tag = hex!("843122130f7364b761e0b97427e3df28");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..8], &ct);
+ assert_eq!(&result[8..], &tag);
+ assert_eq!(A::TAG_SIZE, result[8..].len());
+ let result = aes.decrypt(&result[..], b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-256-GCM-SIV encryption/decryption
+pub fn aes_256_gcm_siv_test_tc77_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
// https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
// TC77
let test_key = hex!("0100000000000000000000000000000000000000000000000000000000000000");
@@ -59,22 +154,72 @@
buf.extend_from_slice(&msg);
let ct = hex!("c2ef328e5c71c83b");
let tag = hex!("843122130f7364b761e0b97427e3df28");
- assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..8], &ct);
- assert_eq!(&buf[8..], &tag);
- assert_eq!(A::TAG_SIZE, buf[8..].len());
- assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..], &msg);
+ let actual_tag = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(&actual_tag, &tag);
+ assert_eq!(A::TAG_SIZE, tag.len());
+ assert!(aes.decrypt_detached(&mut buf, b"", &nonce, &actual_tag).is_ok());
+ assert_eq!(&buf, &msg);
+}
+
+/// Test AES-256-GCM-SIV encryption/decryption
+pub fn aes_256_gcm_siv_test_tc78<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
// TC78
+ let test_key = hex!("0100000000000000000000000000000000000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
+ let msg = hex!("010000000000000000000000");
+ let ct = hex!("9aab2aeb3faa0a34aea8e2b1");
+ let tag = hex!("8ca50da9ae6559e48fd10f6e5c9ca17e");
+ let result = aes.encrypt(&msg, b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..12], &ct);
+ assert_eq!(&result[12..], &tag);
+ let result = aes.decrypt(&result[..], b"", &nonce).expect("should succeed");
+ assert_eq!(&result[..], &msg);
+}
+
+/// Test AES-256-GCM-SIV encryption/decryption
+pub fn aes_256_gcm_siv_test_tc78_detached<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC78
+ let test_key = hex!("0100000000000000000000000000000000000000000000000000000000000000");
+ let nonce = hex!("030000000000000000000000");
+ let aes = A::new(&test_key.into());
let msg = hex!("010000000000000000000000");
let ct = hex!("9aab2aeb3faa0a34aea8e2b1");
let tag = hex!("8ca50da9ae6559e48fd10f6e5c9ca17e");
let mut buf = Vec::from(msg.as_slice());
- assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..12], &ct);
- assert_eq!(&buf[12..], &tag);
- assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok());
- assert_eq!(&buf[..], &msg);
+ let actual_tag = aes.encrypt_detached(&mut buf, b"", &nonce).unwrap();
+ assert_eq!(&buf, &ct);
+ assert_eq!(&actual_tag, &tag);
+ assert!(aes.decrypt_detached(&mut buf, b"", &nonce, &tag).is_ok());
+ assert_eq!(&buf, &msg);
+}
+
+/// Test AES-256-GCM-SIV encryption/decryption where the tag given to decryption doesn't match.
+pub fn aes_256_gcm_siv_test_decrypt_detached_bad_tag<A>(_marker: marker::PhantomData<A>)
+where
+ A: AesGcmSiv<Tag = [u8; 16]> + AeadInit<crypto_provider::aes::Aes256Key>,
+{
+ // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
+ // TC122
+ let test_key = hex!("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff");
+ let nonce = hex!("000000000000000000000000");
+ let aes = A::new(&test_key.into());
+ let aad = hex!("0289eaa93eb084107d2088435ef2a0cd");
+ let ct = hex!("ffffffffffffffff");
+ let bad_tag = hex!("ffffffffffffffffffffffffffffffff");
+ let mut buf = Vec::from(ct.as_slice());
+ aes.decrypt_detached(&mut buf, &aad, &nonce, &bad_tag)
+ .expect_err("Decrypting with bad tag should fail");
+ assert_eq!(&buf, &ct); // The buffer should be unchanged if the decryption failed
}
/// Generates the test cases to validate the AES-128-GCM-SIV implementation.
@@ -93,13 +238,37 @@
#[template]
#[export]
#[rstest]
-#[case::encrypt(aes_128_gcm_siv_test)]
-#[case::decrypt(aes_128_gcm_siv_test)]
+#[case::encrypt(aes_128_gcm_siv_test_encrypt)]
+#[case::decrypt(aes_128_gcm_siv_test_decrypt)]
fn aes_128_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes128Key>>(
#[case] testcase: CryptoProviderTestCase<F>,
) {
}
+/// Generates the test cases to validate the AES-128-GCM-SIV implementation.
+/// For example, to test `MyAesGcmSiv128Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm_siv::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_128_gcm_siv_test_cases_detached)]
+/// fn aes_128_gcm_siv_tests(testcase: CryptoProviderTestCase<MyAesGcmSivImpl>) {
+/// testcase(MyAesGcmSiv128Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::encrypt_detached(aes_128_gcm_siv_test_encrypt_detached)]
+#[case::decrypt_detached(aes_128_gcm_siv_test_decrypt_detached)]
+#[case::decrypt_detached_bad_tag(aes_128_gcm_siv_test_decrypt_detached_bad_tag)]
+fn aes_128_gcm_siv_test_cases_detached<F: AesGcmSivFactory<Key = Aes128Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
+
/// Generates the test cases to validate the AES-256-GCM-SIV implementation.
/// For example, to test `MyAesGcmSiv256Impl`:
///
@@ -116,9 +285,33 @@
#[template]
#[export]
#[rstest]
-#[case::encrypt(aes_256_gcm_siv_test)]
-#[case::decrypt(aes_256_gcm_siv_test)]
+#[case::tc77(aes_256_gcm_siv_test_tc77)]
+#[case::tc78(aes_256_gcm_siv_test_tc78)]
fn aes_256_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes256Key>>(
#[case] testcase: CryptoProviderTestCase<F>,
) {
}
+
+/// Generates the test cases to validate the AES-256-GCM-SIV implementation.
+/// For example, to test `MyAesGcmSiv256Impl`:
+///
+/// ```
+/// use crypto_provider::aes::aes_gcm_siv::testing::*;
+///
+/// mod tests {
+/// #[apply(aes_256_gcm_siv_test_cases_detached)]
+/// fn aes_256_gcm_siv_tests(testcase: CryptoProviderTestCase<MyAesGcmSiv256Impl>) {
+/// testcase(MyAesGcmSiv256Impl);
+/// }
+/// }
+/// ```
+#[template]
+#[export]
+#[rstest]
+#[case::tc77_detached(aes_256_gcm_siv_test_tc77_detached)]
+#[case::tc78_detached(aes_256_gcm_siv_test_tc78_detached)]
+#[case::decrypt_detached_bad_tag(aes_256_gcm_siv_test_decrypt_detached_bad_tag)]
+fn aes_256_gcm_siv_test_cases_detached<F: AesGcmSivFactory<Key = Aes256Key>>(
+ #[case] testcase: CryptoProviderTestCase<F>,
+) {
+}
diff --git a/nearby/crypto/crypto_provider_test/src/aead/mod.rs b/nearby/crypto/crypto_provider_test/src/aead/mod.rs
index 962aa49..3fe857c 100644
--- a/nearby/crypto/crypto_provider_test/src/aead/mod.rs
+++ b/nearby/crypto/crypto_provider_test/src/aead/mod.rs
@@ -14,3 +14,6 @@
/// Contains test cases for aes_gcm_siv implementations.
pub mod aes_gcm_siv;
+
+/// Contains test cases for aes_gcm implementations.
+pub mod aes_gcm;
diff --git a/nearby/crypto/crypto_provider_test/src/aes/cbc.rs b/nearby/crypto/crypto_provider_test/src/aes/cbc.rs
index b22c828..46cbebe 100644
--- a/nearby/crypto/crypto_provider_test/src/aes/cbc.rs
+++ b/nearby/crypto/crypto_provider_test/src/aes/cbc.rs
@@ -15,13 +15,17 @@
use crate::aes::Aes256Key;
pub use crate::prelude::*;
use core::marker::PhantomData;
-use crypto_provider::aes::cbc::{AesCbcIv, AesCbcPkcs7Padded};
+use crypto_provider::{
+ aes::cbc::{AesCbcIv, AesCbcPkcs7Padded},
+ tinyvec::SliceVec,
+};
use hex_literal::hex;
use rstest_reuse::template;
/// Tests for AES-256-CBC encryption
pub fn aes_256_cbc_test_encrypt<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
- // http://google3/third_party/wycheproof/testvectors/aes_cbc_pkcs5_test.json;l=1492;rcl=264817632
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1492
+ // tcId: 132
let key: Aes256Key =
hex!("665a02bc265a66d01775091da56726b6668bfd903cb7af66fb1b78a8a062e43c").into();
let iv: AesCbcIv = hex!("3fb0d5ecd06c71150748b599595833cb");
@@ -30,9 +34,47 @@
assert_eq!(A::encrypt(&key, &iv, &msg), expected_ciphertext);
}
+/// Tests for AES-256-CBC in-place encryption
+pub fn aes_256_cbc_test_encrypt_in_place<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1492
+ // tcId: 132
+ let key: Aes256Key =
+ hex!("665a02bc265a66d01775091da56726b6668bfd903cb7af66fb1b78a8a062e43c").into();
+ let iv: AesCbcIv = hex!("3fb0d5ecd06c71150748b599595833cb");
+ let msg = hex!("3f56935def3f");
+ let expected_ciphertext = hex!("3f3f39697bd7e88d85a14132be1cbc48");
+ let mut msg_buffer_backing = [0_u8; 16];
+ let mut msg_buffer = SliceVec::from_slice_len(&mut msg_buffer_backing, 0);
+ msg_buffer.extend_from_slice(&msg);
+ A::encrypt_in_place(&key, &iv, &mut msg_buffer).unwrap();
+ assert_eq!(msg_buffer.as_slice(), &expected_ciphertext);
+}
+
+/// Tests for AES-256-CBC encryption, where the given buffer `SliceVec` is too short to contain the
+/// output.
+pub fn aes_256_cbc_test_encrypt_in_place_too_short<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1612
+ // tcId: 144
+ let key: Aes256Key =
+ hex!("4f097858a1aec62cf18f0966b2b120783aa4ae9149d3213109740506ae47adfe").into();
+ let iv: AesCbcIv = hex!("400aab92803bcbb44a96ef789655b34e");
+ let msg = hex!("ee53d8e5039e82d9fcca114e375a014febfea117a7e709d9008d43858e3660");
+ let mut msg_buffer_backing = [0_u8; 31];
+ let mut msg_buffer = SliceVec::from_slice_len(&mut msg_buffer_backing, 0);
+ msg_buffer.extend_from_slice(&msg);
+ A::encrypt_in_place(&key, &iv, &mut msg_buffer)
+ .expect_err("Encrypting AES with 15-byte buffer should fail");
+ // Buffer content is undefined, but test to make sure it doesn't contain half-decrypted data
+ assert!(
+ msg_buffer.as_slice() == [0_u8; 32] || msg_buffer.as_slice() == msg,
+ "Unrecognized content in buffer after decryption failure"
+ )
+}
+
/// Tests for AES-256-CBC decryption
pub fn aes_256_cbc_test_decrypt<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
- // http://google3/third_party/wycheproof/testvectors/aes_cbc_pkcs5_test.json;l=1492;rcl=264817632
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1492
+ // tcId: 132
let key: Aes256Key =
hex!("665a02bc265a66d01775091da56726b6668bfd903cb7af66fb1b78a8a062e43c").into();
let iv: AesCbcIv = hex!("3fb0d5ecd06c71150748b599595833cb");
@@ -41,6 +83,52 @@
assert_eq!(A::decrypt(&key, &iv, &ciphertext).unwrap(), expected_msg);
}
+/// Tests for AES-256-CBC decryption with bad padding
+pub fn aes_256_cbc_test_decrypt_bad_padding<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1690
+ // tcId: 151
+ let key: Aes256Key =
+ hex!("7c78f34dbce8f0557d43630266f59babd1cb92ba624bd1a8f45a2a91c84a804a").into();
+ let iv: AesCbcIv = hex!("f010f61c31c9aa8fa0d5be5f6b0f2f70");
+ let ciphertext = hex!("8881e9e02fa9e3037b397957ba1fb7ce64679a46621b792f643542a735f0bbbf");
+ A::decrypt(&key, &iv, &ciphertext).expect_err("Decryption with bad padding should fail");
+}
+
+/// Tests for AES-256-CBC in-place decryption
+pub fn aes_256_cbc_test_decrypt_in_place<A: AesCbcPkcs7Padded>(_marker: PhantomData<A>) {
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1492
+ // tcId: 132
+ let key: Aes256Key =
+ hex!("665a02bc265a66d01775091da56726b6668bfd903cb7af66fb1b78a8a062e43c").into();
+ let iv: AesCbcIv = hex!("3fb0d5ecd06c71150748b599595833cb");
+ let mut ciphertext = hex!("3f3f39697bd7e88d85a14132be1cbc48");
+ let expected_msg = hex!("3f56935def3f");
+ let mut msg_buffer = SliceVec::from(&mut ciphertext);
+ A::decrypt_in_place(&key, &iv, &mut msg_buffer).unwrap();
+ assert_eq!(msg_buffer.as_slice(), expected_msg);
+}
+
+/// Tests for AES-256-CBC in-place decryption with bad padding
+pub fn aes_256_cbc_test_decrypt_in_place_bad_padding<A: AesCbcPkcs7Padded>(
+ _marker: PhantomData<A>,
+) {
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/aes_cbc_pkcs5_test.json#L1690
+ // tcId: 151
+ let key: Aes256Key =
+ hex!("7c78f34dbce8f0557d43630266f59babd1cb92ba624bd1a8f45a2a91c84a804a").into();
+ let iv: AesCbcIv = hex!("f010f61c31c9aa8fa0d5be5f6b0f2f70");
+ let ciphertext = hex!("8881e9e02fa9e3037b397957ba1fb7ce64679a46621b792f643542a735f0bbbf");
+ let mut msg_buffer_backing = ciphertext;
+ let mut msg_buffer = SliceVec::from(&mut msg_buffer_backing);
+ A::decrypt_in_place(&key, &iv, &mut msg_buffer)
+ .expect_err("Decryption with bad padding should fail");
+ // Buffer content is undefined, but test to make sure it doesn't contain half-decrypted data
+ assert!(
+ msg_buffer.as_slice() == [0_u8; 32] || msg_buffer.as_slice() == ciphertext,
+ "Unrecognized content in buffer after decryption failure"
+ )
+}
+
/// Generates the test cases to validate the AES-256-CBC implementation.
/// For example, to test `MyAesCbc256Impl`:
///
@@ -59,5 +147,9 @@
#[export]
#[rstest]
#[case::encrypt(aes_256_cbc_test_encrypt)]
+#[case::encrypt_in_place(aes_256_cbc_test_encrypt_in_place)]
+#[case::encrypt_in_place_too_short(aes_256_cbc_test_encrypt_in_place_too_short)]
#[case::decrypt(aes_256_cbc_test_decrypt)]
+#[case::decrypt_bad_padding(aes_256_cbc_test_decrypt_bad_padding)]
+#[case::decrypt_in_place_bad_padding(aes_256_cbc_test_decrypt_in_place_bad_padding)]
fn aes_256_cbc_test_cases<A: AesCbcPkcs7Padded>(#[case] testcase: CryptoProviderTestCases<F>) {}
diff --git a/nearby/crypto/crypto_provider_test/src/aes/ctr.rs b/nearby/crypto/crypto_provider_test/src/aes/ctr.rs
index b1d6b8b..de71740 100644
--- a/nearby/crypto/crypto_provider_test/src/aes/ctr.rs
+++ b/nearby/crypto/crypto_provider_test/src/aes/ctr.rs
@@ -27,22 +27,22 @@
let mut cipher = A::new(&key, NonceAndCounter::from_block(iv));
block = hex!("6bc1bee22e409f96e93d7e117393172a");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_1 = hex!("874d6191b620e3261bef6864990db6ce");
assert_eq!(expected_ciphertext_1, block);
block = hex!("ae2d8a571e03ac9c9eb76fac45af8e51");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_2 = hex!("9806f66b7970fdff8617187bb9fffdff");
assert_eq!(expected_ciphertext_2, block);
block = hex!("30c81c46a35ce411e5fbc1191a0a52ef");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_3 = hex!("5ae4df3edbd5d35e5b4f09020db03eab");
assert_eq!(expected_ciphertext_3, block);
block = hex!("f69f2445df4f9b17ad2b417be66c3710");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_3 = hex!("1e031dda2fbe03d1792170a0f3009cee");
assert_eq!(expected_ciphertext_3, block);
}
@@ -56,22 +56,22 @@
let mut cipher = A::new(&key, NonceAndCounter::from_block(iv));
block = hex!("874d6191b620e3261bef6864990db6ce");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_1 = hex!("6bc1bee22e409f96e93d7e117393172a");
assert_eq!(expected_plaintext_1, block);
block = hex!("9806f66b7970fdff8617187bb9fffdff");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_2 = hex!("ae2d8a571e03ac9c9eb76fac45af8e51");
assert_eq!(expected_plaintext_2, block);
block = hex!("5ae4df3edbd5d35e5b4f09020db03eab");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_3 = hex!("30c81c46a35ce411e5fbc1191a0a52ef");
assert_eq!(expected_plaintext_3, block);
block = hex!("1e031dda2fbe03d1792170a0f3009cee");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_3 = hex!("f69f2445df4f9b17ad2b417be66c3710");
assert_eq!(expected_plaintext_3, block);
}
@@ -86,22 +86,22 @@
let mut cipher = A::new(&key, NonceAndCounter::from_block(iv));
block = hex!("6bc1bee22e409f96e93d7e117393172a");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_1 = hex!("601ec313775789a5b7a7f504bbf3d228");
assert_eq!(expected_ciphertext_1, block);
block = hex!("ae2d8a571e03ac9c9eb76fac45af8e51");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_2 = hex!("f443e3ca4d62b59aca84e990cacaf5c5");
assert_eq!(expected_ciphertext_2, block);
block = hex!("30c81c46a35ce411e5fbc1191a0a52ef");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_3 = hex!("2b0930daa23de94ce87017ba2d84988d");
assert_eq!(expected_ciphertext_3, block);
block = hex!("f69f2445df4f9b17ad2b417be66c3710");
- cipher.encrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_ciphertext_3 = hex!("dfc9c58db67aada613c2dd08457941a6");
assert_eq!(expected_ciphertext_3, block);
}
@@ -116,22 +116,22 @@
let mut cipher = A::new(&key, NonceAndCounter::from_block(iv));
block = hex!("601ec313775789a5b7a7f504bbf3d228");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_1 = hex!("6bc1bee22e409f96e93d7e117393172a");
assert_eq!(expected_plaintext_1, block);
block = hex!("f443e3ca4d62b59aca84e990cacaf5c5");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_2 = hex!("ae2d8a571e03ac9c9eb76fac45af8e51");
assert_eq!(expected_plaintext_2, block);
block = hex!("2b0930daa23de94ce87017ba2d84988d");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_3 = hex!("30c81c46a35ce411e5fbc1191a0a52ef");
assert_eq!(expected_plaintext_3, block);
block = hex!("dfc9c58db67aada613c2dd08457941a6");
- cipher.decrypt(&mut block);
+ cipher.apply_keystream(&mut block);
let expected_plaintext_3 = hex!("f69f2445df4f9b17ad2b417be66c3710");
assert_eq!(expected_plaintext_3, block);
}
diff --git a/nearby/crypto/crypto_provider_test/src/ed25519.rs b/nearby/crypto/crypto_provider_test/src/ed25519.rs
index d99605c..0fdb484 100644
--- a/nearby/crypto/crypto_provider_test/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider_test/src/ed25519.rs
@@ -18,7 +18,9 @@
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
-use crypto_provider::ed25519::{Ed25519Provider, KeyPair, PublicKey, Signature};
+use crypto_provider::ed25519::{
+ Ed25519Provider, KeyPair, PublicKey, RawPrivateKeyPermit, RawSignature, Signature,
+};
use wycheproof::TestResult;
// These are test vectors from the creators of Ed25519: https://ed25519.cr.yp.to/ which are referenced
@@ -27,7 +29,7 @@
// also used for test cases in the above RFC:
// https://dev.gnupg.org/source/libgcrypt/browse/master/tests/t-ed25519.inp
const PATH_TO_RFC_VECTORS_FILE: &str =
- "crypto/crypto_provider_test/src/testdata/ecdsa/rfc_test_vectors.txt";
+ "crypto/crypto_provider_test/src/testdata/EdDSA/rfc_test_vectors.txt";
/// Runs set of Ed25519 wycheproof test vectors against a provided ed25519 implementation
/// Tests vectors from Project Wycheproof: <https://github.com/google/wycheproof>
@@ -39,10 +41,7 @@
.expect("should be able to load test set");
for test_group in test_set.test_groups {
- let key_pair = test_group.key;
- let public_key = key_pair.pk;
- let secret_key = key_pair.sk;
-
+ let public_key = test_group.key.pk.to_vec();
for test in test_group.tests {
let tc_id = test.tc_id;
let comment = test.comment;
@@ -53,8 +52,7 @@
TestResult::Invalid => false,
TestResult::Valid | TestResult::Acceptable => true,
};
- let result =
- run_test::<E>(public_key.clone(), secret_key.clone(), sig.clone(), msg.clone());
+ let result = run_wycheproof_test::<E>(public_key.to_vec(), sig.to_vec(), msg.to_vec());
if valid {
if let Err(desc) = result {
panic!(
@@ -73,6 +71,20 @@
}
}
+fn run_wycheproof_test<E>(pub_key: Vec<u8>, sig: Vec<u8>, msg: Vec<u8>) -> Result<(), &'static str>
+where
+ E: Ed25519Provider,
+{
+ let pub_key = E::PublicKey::from_bytes(pub_key.as_slice().try_into().unwrap())
+ .map_err(|_| "Invalid public key bytes")?;
+
+ let raw_sig: RawSignature =
+ sig.as_slice().try_into().map_err(|_| "Invalid length signature")?;
+ let signature = E::Signature::from_bytes(&raw_sig);
+
+ pub_key.verify_strict(msg.as_slice(), &signature).map_err(|_| "Signature verification failed")
+}
+
/// Runs the RFC specified test vectors against an Ed25519 implementation
pub fn run_rfc_test_vectors<E>()
where
@@ -126,7 +138,10 @@
{
let private_key_bytes: [u8; 32] =
private_key.as_slice().try_into().expect("Secret key is the wrong length");
- let kp = E::KeyPair::from_private_key(&private_key_bytes);
+
+ // Permits: Test-only code, not a production leak of the private key
+ let permit = RawPrivateKeyPermit::default();
+ let kp = E::KeyPair::from_raw_private_key(&private_key_bytes, &permit);
let sig_result = kp.sign(msg.as_slice());
(sig.as_slice() == sig_result.to_bytes()).then_some(()).ok_or("sig not matching expected")?;
diff --git a/nearby/crypto/crypto_provider_test/src/lib.rs b/nearby/crypto/crypto_provider_test/src/lib.rs
index 8e63f44..2209a3e 100644
--- a/nearby/crypto/crypto_provider_test/src/lib.rs
+++ b/nearby/crypto/crypto_provider_test/src/lib.rs
@@ -36,9 +36,11 @@
/// Common items that needs to be imported to use these test cases
pub mod prelude {
pub use super::CryptoProviderTestCase;
+ pub use ::rstest;
pub use rstest::rstest;
pub use rstest_reuse;
pub use rstest_reuse::apply;
+ pub extern crate std;
}
/// A test case for Crypto Provider. A test case is a function that panics if the test fails.
diff --git a/nearby/crypto/crypto_provider_test/src/p256.rs b/nearby/crypto/crypto_provider_test/src/p256.rs
index 9869c9e..5ebbd50 100644
--- a/nearby/crypto/crypto_provider_test/src/p256.rs
+++ b/nearby/crypto/crypto_provider_test/src/p256.rs
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate std;
use crate::elliptic_curve::EphemeralSecretForTesting;
pub use crate::prelude::*;
use crate::TestError;
use core::marker::PhantomData;
-use crypto_provider::p256::{P256PublicKey, P256};
+use core::ops::Deref;
+use crypto_provider::p256::{P256PublicKey, PointCompression, P256};
use crypto_provider::{
elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey},
CryptoRng,
@@ -62,9 +62,35 @@
8bbe76c6dc1643088107636deff8aa79e8002a157b92"
);
let key = E::PublicKey::from_sec1_bytes(&sec1_bytes).unwrap();
+ // Not part of the API contract, but `to_bytes()` should prefer to use uncompressed
+ // representation since support for compressed point is optional.
+ let key_bytes = key.to_bytes();
+ assert_eq!(sec1_bytes.to_vec(), key_bytes.deref());
+}
+
+/// Test for P256PublicKey::to_sec1_bytes(Compressed). Support for compressed representation is
+/// optional.
+pub fn to_bytes_compressed_test<E: EcdhProviderForP256Test>(_: PhantomData<E>) {
+ let sec1_bytes = hex!(
+ "04756c07ba5b596fa96c9099e6619dc62deac4297a8fc1d803d74dc5caa9197c09f0b6da270d2a58a06022
+ 8bbe76c6dc1643088107636deff8aa79e8002a157b92"
+ );
+ let key = E::PublicKey::from_sec1_bytes(&sec1_bytes).unwrap();
+ let key_bytes = key.to_sec1_bytes(PointCompression::Compressed);
let sec1_bytes_compressed =
hex!("02756c07ba5b596fa96c9099e6619dc62deac4297a8fc1d803d74dc5caa9197c09");
- assert_eq!(sec1_bytes_compressed.to_vec(), key.to_bytes());
+ assert_eq!(sec1_bytes_compressed.to_vec(), key_bytes.deref());
+}
+
+/// Test for P256PublicKey::to_sec1_bytes(Uncompressed)
+pub fn to_bytes_uncompressed_test<E: EcdhProviderForP256Test>(_: PhantomData<E>) {
+ let sec1_bytes = hex!(
+ "04756c07ba5b596fa96c9099e6619dc62deac4297a8fc1d803d74dc5caa9197c09f0b6da270d2a58a06022
+ 8bbe76c6dc1643088107636deff8aa79e8002a157b92"
+ );
+ let key = E::PublicKey::from_sec1_bytes(&sec1_bytes).unwrap();
+ let key_bytes = key.to_sec1_bytes(PointCompression::Uncompressed);
+ assert_eq!(sec1_bytes.to_vec(), key_bytes.deref());
}
/// Random test for P256PublicKey::to_bytes
@@ -75,7 +101,7 @@
P256,
>>::Rng::new())
.public_key_bytes();
- let public_key = E::PublicKey::from_bytes(&public_key_bytes).unwrap();
+ let public_key = E::PublicKey::from_bytes(public_key_bytes.as_ref()).unwrap();
assert_eq!(
E::PublicKey::from_bytes(&public_key.to_bytes()).unwrap(),
public_key,
@@ -192,7 +218,7 @@
/// Test for P256 Diffie-Hellman key exchange.
pub fn p256_ecdh_test<E: EcdhProviderForP256Test>(_: PhantomData<E>) {
// From wycheproof ecdh_secp256r1_ecpoint_test.json, tcId 1
- // http://google3/third_party/wycheproof/testvectors/ecdh_secp256r1_ecpoint_test.json;l=22;rcl=375894991
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/ecdh_secp256r1_ecpoint_test.json#L22
// sec1 public key manually extracted from the ASN encoded test data
let public_key_sec1 = hex!(
"0462d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f
@@ -230,20 +256,24 @@
};
let result = p256_ecdh_test_impl::<E>(
&test.public_key,
- &test.private_key.try_into().expect("Private key should be 32 bytes long"),
+ &test
+ .private_key
+ .as_slice()
+ .try_into()
+ .expect("Private key should be 32 bytes long"),
);
match test.result {
wycheproof::TestResult::Valid => {
let shared_secret =
result.unwrap_or_else(|_| panic!("Test {} should succeed", test.tc_id));
- assert_eq!(test.shared_secret, shared_secret.into());
+ assert_eq!(test.shared_secret.as_slice(), shared_secret.into());
}
wycheproof::TestResult::Invalid => {
result.err().unwrap_or_else(|| panic!("Test {} should fail", test.tc_id));
}
wycheproof::TestResult::Acceptable => {
if let Ok(shared_secret) = result {
- assert_eq!(test.shared_secret, shared_secret.into());
+ assert_eq!(test.shared_secret.as_slice(), shared_secret.into());
}
// Test passes if `result` is an error because this test is "acceptable"
}
@@ -268,22 +298,43 @@
#[template]
#[export]
#[rstest]
-#[case::to_bytes(to_bytes_test)]
-#[case::to_bytes_random(to_bytes_random_test)]
-#[case::from_sec1_bytes_not_on_curve(from_sec1_bytes_not_on_curve_test)]
-#[case::from_sec1_bytes_not_on_infinity(from_sec1_bytes_at_infinity_test)]
-#[case::from_affine_coordinates(from_affine_coordinates_test)]
-#[case::from_affine_coordinates_not_on_curve(from_affine_coordinates_not_on_curve_test)]
-#[case::public_key_to_affine_coordinates(public_key_to_affine_coordinates_test)]
+#[case::to_bytes(to_bytes_test, "to_bytes")]
+#[case::to_bytes_compressed(to_bytes_compressed_test, "to_bytes_compressed")]
+#[case::to_bytes_uncompressed(to_bytes_uncompressed_test, "to_bytes_uncompressed")]
+#[case::to_bytes_random(to_bytes_random_test, "to_bytes_random")]
+#[case::from_sec1_bytes_not_on_curve(
+ from_sec1_bytes_not_on_curve_test,
+ "from_sec1_bytes_not_on_curve"
+)]
+#[case::from_sec1_bytes_not_on_infinity(
+ from_sec1_bytes_at_infinity_test,
+ "from_sec1_bytes_not_on_infinity"
+)]
+#[case::from_affine_coordinates(from_affine_coordinates_test, "from_affine_coordinates")]
+#[case::from_affine_coordinates_not_on_curve(
+ from_affine_coordinates_not_on_curve_test,
+ "from_affine_coordinates_not_on_curve"
+)]
+#[case::public_key_to_affine_coordinates(
+ public_key_to_affine_coordinates_test,
+ "public_key_to_affine_coordinates"
+)]
#[case::public_key_to_affine_coordinates_compressed02(
- public_key_to_affine_coordinates_compressed02_test
+ public_key_to_affine_coordinates_compressed02_test,
+ "public_key_to_affine_coordinates_compressed02"
)]
#[case::public_key_to_affine_coordinates_compressed03(
- public_key_to_affine_coordinates_compressed03_test
+ public_key_to_affine_coordinates_compressed03_test,
+ "public_key_to_affine_coordinates_compressed03"
)]
#[case::public_key_to_affine_coordinates_zero_top_byte(
- public_key_to_affine_coordinates_zero_top_byte_test
+ public_key_to_affine_coordinates_zero_top_byte_test,
+ "public_key_to_affine_coordinates_zero_top_byte"
)]
-#[case::p256_ecdh(p256_ecdh_test)]
-#[case::wycheproof_p256(wycheproof_p256_test)]
-fn p256_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
+#[case::p256_ecdh(p256_ecdh_test, "p256_ecdh")]
+#[case::wycheproof_p256(wycheproof_p256_test, "wycheproof_p256")]
+fn p256_test_cases<C: CryptoProvider>(
+ #[case] testcase: CryptoProviderTestCase<C>,
+ #[case] name: &str,
+) {
+}
diff --git a/nearby/crypto/crypto_provider_test/src/sha2.rs b/nearby/crypto/crypto_provider_test/src/sha2.rs
index 330f284..66a3025 100644
--- a/nearby/crypto/crypto_provider_test/src/sha2.rs
+++ b/nearby/crypto/crypto_provider_test/src/sha2.rs
@@ -14,7 +14,7 @@
extern crate alloc;
extern crate std;
-pub use crate::prelude::*;
+use crate::prelude::*;
use crate::CryptoProvider;
use alloc::vec::Vec;
use core::{marker::PhantomData, str::FromStr};
diff --git a/nearby/crypto/crypto_provider_test/src/testdata/ecdsa/rfc_test_vectors.txt b/nearby/crypto/crypto_provider_test/src/testdata/EdDSA/rfc_test_vectors.txt
similarity index 100%
rename from nearby/crypto/crypto_provider_test/src/testdata/ecdsa/rfc_test_vectors.txt
rename to nearby/crypto/crypto_provider_test/src/testdata/EdDSA/rfc_test_vectors.txt
diff --git a/nearby/crypto/crypto_provider_test/src/x25519.rs b/nearby/crypto/crypto_provider_test/src/x25519.rs
index 0fcaa12..1fe2019 100644
--- a/nearby/crypto/crypto_provider_test/src/x25519.rs
+++ b/nearby/crypto/crypto_provider_test/src/x25519.rs
@@ -58,7 +58,7 @@
pub fn x25519_to_bytes_test<E: EcdhProviderForX25519Test>(_: PhantomData<E>) {
let public_key_bytes = hex!("504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829");
let public_key = E::PublicKey::from_bytes(&public_key_bytes).unwrap();
- assert_eq!(public_key_bytes.to_vec(), public_key.to_bytes());
+ assert_eq!(public_key_bytes.to_vec(), public_key.to_bytes().as_ref());
}
/// Random test for `PublicKey<X25519>::to_bytes`
@@ -69,9 +69,9 @@
X25519,
>>::Rng::new())
.public_key_bytes();
- let public_key = E::PublicKey::from_bytes(&public_key_bytes).unwrap();
+ let public_key = E::PublicKey::from_bytes(public_key_bytes.as_ref()).unwrap();
assert_eq!(
- E::PublicKey::from_bytes(&public_key.to_bytes()).unwrap(),
+ E::PublicKey::from_bytes(public_key.to_bytes().as_ref()).unwrap(),
public_key,
"from_bytes should return the same key for `{public_key_bytes:?}`",
);
@@ -81,7 +81,7 @@
/// Test for X25519 Diffie-Hellman key exchange.
pub fn x25519_ecdh_test<E: EcdhProviderForX25519Test>(_: PhantomData<E>) {
// From wycheproof ecdh_secx25519r1_ecpoint_test.json, tcId 1
- // http://google3/third_party/wycheproof/testvectors/ecdh_secx25519r1_ecpoint_test.json;l=22;rcl=375894991
+ // https://github.com/google/wycheproof/blob/b063b4a/testvectors/x25519_test.json#L23
// sec1 public key manually extracted from the ASN encoded test data
let public_key = hex!("504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829");
let private = hex!("c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475");
@@ -109,20 +109,24 @@
for test in test_group.tests {
let result = x25519_ecdh_test_impl::<E>(
&test.public_key,
- &test.private_key.try_into().expect("Private keys should be 32 bytes long"),
+ &test
+ .private_key
+ .as_slice()
+ .try_into()
+ .expect("Private keys should be 32 bytes long"),
);
match test.result {
wycheproof::TestResult::Valid => {
let shared_secret =
result.unwrap_or_else(|_| panic!("Test {} should succeed", test.tc_id));
- assert_eq!(&test.shared_secret, &shared_secret.into());
+ assert_eq!(&test.shared_secret.as_slice(), &shared_secret.into());
}
wycheproof::TestResult::Invalid => {
result.err().unwrap_or_else(|| panic!("Test {} should fail", test.tc_id));
}
wycheproof::TestResult::Acceptable => {
if let Ok(shared_secret) = result {
- assert_eq!(test.shared_secret, shared_secret.into());
+ assert_eq!(test.shared_secret.as_slice(), shared_secret.into());
}
// Test passes if `result` is an error because this test is "acceptable"
}