Replaces Rng256 with new Rng API (#612)

* Replaces the Rng256 with RngCore from rand_core

The old trait was designed with our software crypto in mind. We should
use a more standard API going forward.

- Removes libraries/rng256/
- Ports libraries/crypto/ to rand_core
- Moves the used RNG trait to api/

* Use StdRng directy in TestEnv
This commit is contained in:
kaczmarczyck
2023-04-11 10:23:38 +02:00
committed by GitHub
parent 4cc1b4fddf
commit be42b47caf
34 changed files with 219 additions and 536 deletions

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use super::EC_FIELD_SIZE;
use rng256::Rng256;
use crate::api::rng::Rng;
/// Container for all ECDH cryptographic material.
pub trait Ecdh {
@@ -28,7 +28,7 @@ pub trait SecretKey {
type SharedSecret: SharedSecret;
/// Generates a new random secret key.
fn random(rng: &mut impl Rng256) -> Self;
fn random(rng: &mut impl Rng) -> Self;
/// Computes the corresponding public key for this private key.
fn public_key(&self) -> Self::PublicKey;

View File

@@ -13,8 +13,8 @@
// limitations under the License.
use super::{EC_FIELD_SIZE, EC_SIGNATURE_SIZE};
use crate::api::rng::Rng;
use alloc::vec::Vec;
use rng256::Rng256;
/// Container for all ECDSA cryptographic material.
pub trait Ecdsa {
@@ -29,7 +29,7 @@ pub trait SecretKey: Sized {
type Signature: Signature;
/// Generates a new random secret key.
fn random(rng: &mut impl Rng256) -> Self;
fn random(rng: &mut impl Rng) -> Self;
/// Creates a signing key from its representation in bytes.
fn from_slice(bytes: &[u8; EC_FIELD_SIZE]) -> Option<Self>;

View File

@@ -72,6 +72,7 @@ mod test {
use crate::api::crypto::ecdh::{PublicKey as _, SecretKey as _, SharedSecret};
use crate::api::crypto::ecdsa::{PublicKey as _, SecretKey as _};
use crate::env::test::TestEnv;
use crate::env::Env;
use core::convert::TryFrom;
#[test]
@@ -143,7 +144,7 @@ mod test {
assert!(SoftwareHmac256::verify_truncated_left(
&key,
&data,
&truncated_mac
truncated_mac
));
}

View File

@@ -28,6 +28,7 @@ use crate::api::crypto::{
ecdh, ecdsa, Crypto, AES_BLOCK_SIZE, AES_KEY_SIZE, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE,
HMAC_KEY_SIZE, TRUNCATED_HMAC_SIZE,
};
use crate::api::rng::Rng;
use aes::cipher::generic_array::GenericArray;
use aes::cipher::{
BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut, KeyInit, KeyIvInit,
@@ -38,9 +39,6 @@ use p256::ecdh::EphemeralSecret;
use p256::ecdsa::signature::{SignatureEncoding, Signer, Verifier};
use p256::ecdsa::{SigningKey, VerifyingKey};
use p256::elliptic_curve::sec1::ToEncodedPoint;
// TODO: implement CryptoRngCore for our Rng instead
use rand_core::OsRng;
use rng256::Rng256;
use sha2::Digest;
pub struct SoftwareCrypto;
@@ -70,8 +68,8 @@ impl ecdh::SecretKey for SoftwareEcdhSecretKey {
type PublicKey = SoftwareEcdhPublicKey;
type SharedSecret = SoftwareEcdhSharedSecret;
fn random(_rng: &mut impl Rng256) -> Self {
let ephemeral_secret = EphemeralSecret::random(&mut OsRng);
fn random(rng: &mut impl Rng) -> Self {
let ephemeral_secret = EphemeralSecret::random(rng);
Self { ephemeral_secret }
}
@@ -131,8 +129,8 @@ impl ecdsa::SecretKey for SoftwareEcdsaSecretKey {
type PublicKey = SoftwareEcdsaPublicKey;
type Signature = SoftwareEcdsaSignature;
fn random(_rng: &mut impl Rng256) -> Self {
let signing_key = SigningKey::random(&mut OsRng);
fn random(rng: &mut impl Rng) -> Self {
let signing_key = SigningKey::random(rng);
SoftwareEcdsaSecretKey { signing_key }
}
@@ -273,7 +271,7 @@ pub struct SoftwareAes256 {
impl Aes256 for SoftwareAes256 {
fn new(key: &[u8; AES_KEY_SIZE]) -> Self {
SoftwareAes256 { key: key.clone() }
SoftwareAes256 { key: *key }
}
fn encrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]) {

View File

@@ -20,9 +20,9 @@ use crate::api::crypto::{
ecdh, ecdsa, Crypto, AES_BLOCK_SIZE, AES_KEY_SIZE, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE,
HMAC_KEY_SIZE, TRUNCATED_HMAC_SIZE,
};
use crate::api::rng::Rng;
use alloc::vec::Vec;
use crypto::Hash256;
use rng256::Rng256;
pub struct SoftwareCrypto;
pub struct SoftwareEcdh;
@@ -51,7 +51,7 @@ impl ecdh::SecretKey for SoftwareEcdhSecretKey {
type PublicKey = SoftwareEcdhPublicKey;
type SharedSecret = SoftwareEcdhSharedSecret;
fn random(rng: &mut impl Rng256) -> Self {
fn random(rng: &mut impl Rng) -> Self {
let sec_key = crypto::ecdh::SecKey::gensk(rng);
Self { sec_key }
}
@@ -105,7 +105,7 @@ impl ecdsa::SecretKey for SoftwareEcdsaSecretKey {
type PublicKey = SoftwareEcdsaPublicKey;
type Signature = SoftwareEcdsaSignature;
fn random(rng: &mut impl Rng256) -> Self {
fn random(rng: &mut impl Rng) -> Self {
let sec_key = crypto::ecdsa::SecKey::gensk(rng);
Self { sec_key }
}

View File

@@ -13,10 +13,10 @@
// limitations under the License.
use crate::api::crypto::ecdsa::SecretKey as _;
use crate::api::rng::Rng;
use crate::env::{EcdsaSk, Env};
use alloc::vec::Vec;
use persistent_store::StoreError;
use rng256::Rng256;
/// Provides storage for secret keys.
///

View File

@@ -24,5 +24,6 @@ pub mod crypto;
pub mod customization;
pub mod firmware_protection;
pub mod key_store;
pub mod rng;
pub mod upgrade_storage;
pub mod user_presence;

View File

@@ -0,0 +1,30 @@
// 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 rand_core::{CryptoRng, RngCore};
/// Random number generator.
///
/// Reuses the common API from `RngCore`. Implementing the marker trait `CryptoRng` asserts that
/// your random output is usable for sensitive key material.
pub trait Rng: CryptoRng + RngCore {
/// Provides a random byte array.
///
/// This is a convenience function, as CTAP often requires such keys or tokens.
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut bytes = [0; 32];
self.fill_bytes(&mut bytes);
bytes
}
}

View File

@@ -116,8 +116,8 @@ pub struct ClientPin<E: Env> {
impl<E: Env> ClientPin<E> {
pub fn new(env: &mut E) -> Self {
ClientPin {
pin_protocol_v1: PinProtocol::new(env.rng()),
pin_protocol_v2: PinProtocol::new(env.rng()),
pin_protocol_v1: PinProtocol::new(env),
pin_protocol_v2: PinProtocol::new(env),
consecutive_pin_mismatches: 0,
pin_uv_auth_token_state: PinUvAuthTokenState::new(),
}
@@ -176,7 +176,7 @@ impl<E: Env> ClientPin<E> {
if !bool::from(pin_hash.ct_eq(&pin_hash_dec)) {
self.get_mut_pin_protocol(pin_uv_auth_protocol)
.regenerate(env.rng());
.regenerate(env);
if storage::pin_retries(env)? == 0 {
return Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED);
}
@@ -278,8 +278,8 @@ impl<E: Env> ClientPin<E> {
self.verify_pin_hash_enc(env, pin_uv_auth_protocol, &shared_secret, pin_hash_enc)?;
check_and_store_new_pin(env, &shared_secret, new_pin_enc)?;
self.pin_protocol_v1.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v2.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v1.reset_pin_uv_auth_token(env);
self.pin_protocol_v2.reset_pin_uv_auth_token(env);
Ok(())
}
@@ -311,13 +311,13 @@ impl<E: Env> ClientPin<E> {
return Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID);
}
self.pin_protocol_v1.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v2.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v1.reset_pin_uv_auth_token(env);
self.pin_protocol_v2.reset_pin_uv_auth_token(env);
self.pin_uv_auth_token_state
.begin_using_pin_uv_auth_token(env);
self.pin_uv_auth_token_state.set_default_permissions();
let pin_uv_auth_token = shared_secret.encrypt(
env.rng(),
env,
self.get_pin_protocol(pin_uv_auth_protocol)
.get_pin_uv_auth_token(),
)?;
@@ -434,10 +434,10 @@ impl<E: Env> ClientPin<E> {
/// Resets all held state.
pub fn reset(&mut self, env: &mut E) {
self.pin_protocol_v1.regenerate(env.rng());
self.pin_protocol_v1.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v2.regenerate(env.rng());
self.pin_protocol_v2.reset_pin_uv_auth_token(env.rng());
self.pin_protocol_v1.regenerate(env);
self.pin_protocol_v1.reset_pin_uv_auth_token(env);
self.pin_protocol_v2.regenerate(env);
self.pin_protocol_v2.reset_pin_uv_auth_token(env);
self.consecutive_pin_mismatches = 0;
self.pin_uv_auth_token_state.stop_using_pin_uv_auth_token();
}
@@ -476,7 +476,7 @@ impl<E: Env> ClientPin<E> {
let mut output2 = Hmac::<E>::mac(cred_random, &decrypted_salts[32..]).to_vec();
output.append(&mut output2);
}
shared_secret.encrypt(env.rng(), &output)
shared_secret.encrypt(env, &output)
}
/// Consumes flags and permissions related to the pinUvAuthToken.
@@ -563,8 +563,8 @@ impl<E: Env> ClientPin<E> {
pin_uv_auth_token_state.set_permissions(0xFF);
pin_uv_auth_token_state.begin_using_pin_uv_auth_token(env);
Self {
pin_protocol_v1: PinProtocol::<E>::new_test(key_agreement_key_v1, pin_uv_auth_token),
pin_protocol_v2: PinProtocol::<E>::new_test(key_agreement_key_v2, pin_uv_auth_token),
pin_protocol_v1: PinProtocol::new_test(key_agreement_key_v1, pin_uv_auth_token),
pin_protocol_v2: PinProtocol::new_test(key_agreement_key_v2, pin_uv_auth_token),
consecutive_pin_mismatches: 0,
pin_uv_auth_token_state,
}
@@ -594,7 +594,7 @@ mod test {
let mut env = TestEnv::default();
let mut padded_pin = [0u8; 64];
padded_pin[..pin.len()].copy_from_slice(&pin[..]);
shared_secret.encrypt(env.rng(), &padded_pin).unwrap()
shared_secret.encrypt(&mut env, &padded_pin).unwrap()
}
/// Generates a ClientPin instance and a shared secret for testing.
@@ -638,9 +638,9 @@ mod test {
let mut padded_pin = [0u8; 64];
padded_pin[..pin.len()].copy_from_slice(&pin[..]);
let pin_hash = Sha::<TestEnv>::digest(&padded_pin);
let new_pin_enc = shared_secret.encrypt(env.rng(), &padded_pin).unwrap();
let new_pin_enc = shared_secret.encrypt(&mut env, &padded_pin).unwrap();
let pin_uv_auth_param = shared_secret.authenticate(&new_pin_enc);
let pin_hash_enc = shared_secret.encrypt(env.rng(), &pin_hash[..16]).unwrap();
let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash[..16]).unwrap();
let (permissions, permissions_rp_id) = match sub_command {
ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions
| ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions => {
@@ -679,30 +679,30 @@ mod test {
let shared_secret_v2 = pin_protocol_v2
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V2)
.unwrap();
let ciphertext = shared_secret_v1.encrypt(env.rng(), &message).unwrap();
let ciphertext = shared_secret_v1.encrypt(&mut env, &message).unwrap();
let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
let ciphertext = shared_secret_v2.encrypt(env.rng(), &message).unwrap();
let ciphertext = shared_secret_v2.encrypt(&mut env, &message).unwrap();
let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
let fake_secret_v1 = pin_protocol_v1
.decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V1)
.unwrap();
let ciphertext = shared_secret_v1.encrypt(env.rng(), &message).unwrap();
let ciphertext = shared_secret_v1.encrypt(&mut env, &message).unwrap();
let plaintext = fake_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
let ciphertext = fake_secret_v1.encrypt(env.rng(), &message).unwrap();
let ciphertext = fake_secret_v1.encrypt(&mut env, &message).unwrap();
let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
let fake_secret_v2 = pin_protocol_v2
.decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V2)
.unwrap();
let ciphertext = shared_secret_v2.encrypt(env.rng(), &message).unwrap();
let ciphertext = shared_secret_v2.encrypt(&mut env, &message).unwrap();
let plaintext = fake_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
let ciphertext = fake_secret_v2.encrypt(env.rng(), &message).unwrap();
let ciphertext = fake_secret_v2.encrypt(&mut env, &message).unwrap();
let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
assert_ne!(&message, &plaintext);
}
@@ -721,7 +721,7 @@ mod test {
];
storage::set_pin(&mut env, &pin_hash, 4).unwrap();
let pin_hash_enc = shared_secret.encrypt(env.rng(), &pin_hash).unwrap();
let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash).unwrap();
assert_eq!(
client_pin.verify_pin_hash_enc(
&mut env,
@@ -743,7 +743,7 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
);
let pin_hash_enc = shared_secret.encrypt(env.rng(), &pin_hash).unwrap();
let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash).unwrap();
client_pin.consecutive_pin_mismatches = 3;
assert_eq!(
client_pin.verify_pin_hash_enc(
@@ -1147,7 +1147,7 @@ mod test {
fn test_helper_decrypt_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut env = TestEnv::default();
let pin_protocol = PinProtocol::<TestEnv>::new(env.rng());
let pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
let shared_secret = pin_protocol
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
.unwrap();
@@ -1191,7 +1191,7 @@ mod test {
fn test_helper_check_and_store_new_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let mut env = TestEnv::default();
let pin_protocol = PinProtocol::<TestEnv>::new(env.rng());
let pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
let shared_secret = pin_protocol
.decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
.unwrap();
@@ -1250,7 +1250,7 @@ mod test {
let mut env = TestEnv::default();
let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
let salt_enc = shared_secret.encrypt(env.rng(), &salt).unwrap();
let salt_enc = shared_secret.encrypt(&mut env, &salt).unwrap();
let salt_auth = shared_secret.authenticate(&salt_enc);
let hmac_secret_input = GetAssertionHmacSecretInput {
key_agreement: client_pin

View File

@@ -179,7 +179,7 @@ pub fn encrypt_to_credential_id<E: Env>(
add_padding(&mut payload)?;
let aes_key = AesKey::<E>::new(&env.key_store().key_handle_encryption()?);
let encrypted_payload = aes256_cbc_encrypt::<E>(env.rng(), &aes_key, &payload, true)?;
let encrypted_payload = aes256_cbc_encrypt(env, &aes_key, &payload, true)?;
let mut credential_id = encrypted_payload;
credential_id.insert(0, CBOR_CREDENTIAL_ID_VERSION);
@@ -380,7 +380,7 @@ mod test {
/// This is a copy of the function that genereated deprecated key handles.
fn legacy_encrypt_to_credential_id(
env: &mut impl Env,
env: &mut TestEnv,
private_key: EcdsaSk<TestEnv>,
application: &[u8; 32],
) -> Result<Vec<u8>, Ctap2StatusCode> {
@@ -389,8 +389,7 @@ mod test {
private_key.to_slice(array_mut_ref!(plaintext, 0, 32));
plaintext[32..64].copy_from_slice(application);
let mut encrypted_id =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true)?;
let mut encrypted_id = aes256_cbc_encrypt(env, &aes_key, &plaintext, true)?;
let id_hmac = Hmac::<TestEnv>::mac(
&env.key_store().key_handle_authentication()?,
&encrypted_id[..],

View File

@@ -359,9 +359,9 @@ mod test {
use super::super::CtapState;
use super::*;
use crate::api::crypto::ecdh::SecretKey as _;
use crate::api::rng::Rng;
use crate::env::test::TestEnv;
use crate::env::EcdhSk;
use rng256::Rng256;
const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);

View File

@@ -15,19 +15,21 @@
use crate::api::crypto::aes256::Aes256;
use crate::api::crypto::ecdsa::{SecretKey as _, Signature};
use crate::api::key_store::KeyStore;
#[cfg(feature = "ed25519")]
use crate::api::rng::Rng;
use crate::ctap::data_formats::{extract_array, extract_byte_string, CoseKey, SignatureAlgorithm};
use crate::ctap::status_code::Ctap2StatusCode;
use crate::env::{AesKey, EcdsaSk, Env};
use alloc::vec;
use alloc::vec::Vec;
use core::convert::TryFrom;
use rng256::Rng256;
use rand_core::RngCore;
use sk_cbor as cbor;
use sk_cbor::{cbor_array, cbor_bytes, cbor_int};
/// Wraps the AES256-CBC encryption to match what we need in CTAP.
pub fn aes256_cbc_encrypt<E: Env>(
rng: &mut dyn Rng256,
env: &mut E,
aes_key: &AesKey<E>,
plaintext: &[u8],
embeds_iv: bool,
@@ -35,11 +37,10 @@ pub fn aes256_cbc_encrypt<E: Env>(
if plaintext.len() % 16 != 0 {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
// The extra 1 capacity is because encrypt_key_handle adds a version number.
let mut ciphertext = Vec::with_capacity(plaintext.len() + 16 * embeds_iv as usize + 1);
let mut ciphertext = Vec::with_capacity(plaintext.len() + 16 * embeds_iv as usize);
let iv = if embeds_iv {
let random_bytes = rng.gen_uniform_u8x32();
ciphertext.extend_from_slice(&random_bytes[..16]);
ciphertext.resize(16, 0);
env.rng().fill_bytes(&mut ciphertext[..16]);
*array_ref!(ciphertext, 0, 16)
} else {
[0u8; 16]
@@ -227,8 +228,7 @@ mod test {
let mut env = TestEnv::default();
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
let plaintext = vec![0xAA; 64];
let ciphertext =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
let ciphertext = aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, true).unwrap();
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext, true).unwrap();
assert_eq!(decrypted, plaintext);
}
@@ -238,8 +238,7 @@ mod test {
let mut env = TestEnv::default();
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
let plaintext = vec![0xAA; 64];
let ciphertext =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, false).unwrap();
let ciphertext = aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, false).unwrap();
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext, false).unwrap();
assert_eq!(decrypted, plaintext);
}
@@ -250,7 +249,7 @@ mod test {
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
let plaintext = vec![0xAA; 64];
let mut ciphertext_no_iv =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, false).unwrap();
aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, false).unwrap();
let mut ciphertext_with_iv = vec![0u8; 16];
ciphertext_with_iv.append(&mut ciphertext_no_iv);
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext_with_iv, true).unwrap();
@@ -262,8 +261,7 @@ mod test {
let mut env = TestEnv::default();
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
let plaintext = vec![0xAA; 64];
let mut ciphertext =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
let mut ciphertext = aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, true).unwrap();
let mut expected_plaintext = plaintext;
for i in 0..16 {
ciphertext[i] ^= 0xBB;
@@ -278,10 +276,8 @@ mod test {
let mut env = TestEnv::default();
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
let plaintext = vec![0xAA; 64];
let ciphertext1 =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
let ciphertext2 =
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
let ciphertext1 = aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, true).unwrap();
let ciphertext2 = aes256_cbc_encrypt(&mut env, &aes_key, &plaintext, true).unwrap();
assert_eq!(ciphertext1.len(), 80);
assert_eq!(ciphertext2.len(), 80);
// The ciphertext should mutate in all blocks with a different IV.

View File

@@ -1232,13 +1232,13 @@ mod test {
use super::*;
use crate::api::crypto::ecdh::PublicKey as _;
use crate::api::crypto::ecdsa::PublicKey as _;
use crate::api::rng::Rng;
use crate::env::test::TestEnv;
use crate::env::{EcdhPk, EcdsaPk};
use crate::env::{EcdhPk, EcdsaPk, Env};
use cbor::{
cbor_array, cbor_bool, cbor_bytes, cbor_bytes_lit, cbor_false, cbor_int, cbor_null,
cbor_text, cbor_unsigned,
};
use rng256::Rng256;
#[test]
fn test_extract_unsigned() {

View File

@@ -70,6 +70,7 @@ use crate::api::crypto::hmac256::Hmac256;
use crate::api::crypto::sha256::Sha256;
use crate::api::customization::Customization;
use crate::api::firmware_protection::FirmwareProtection;
use crate::api::rng::Rng;
use crate::api::upgrade_storage::UpgradeStorage;
use crate::api::user_presence::{UserPresence, UserPresenceError};
use crate::env::{EcdsaSk, Env, Hmac, Sha};
@@ -79,7 +80,7 @@ use alloc::vec;
use alloc::vec::Vec;
use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom;
use rng256::Rng256;
use rand_core::RngCore;
use sk_cbor as cbor;
use sk_cbor::cbor_map_options;
@@ -510,7 +511,7 @@ impl<E: Env> CtapState<E> {
env: &mut E,
) -> Result<(), Ctap2StatusCode> {
if env.customization().use_signature_counter() {
let increment = env.rng().gen_uniform_u32x8()[0] % 8 + 1;
let increment = env.rng().next_u32() % 8 + 1;
storage::incr_global_signature_counter(env, increment)?;
}
Ok(())
@@ -2414,7 +2415,7 @@ mod test {
.unwrap();
let salt = vec![0x01; 32];
let salt_enc = shared_secret.encrypt(env.rng(), &salt).unwrap();
let salt_enc = shared_secret.encrypt(&mut env, &salt).unwrap();
let salt_auth = shared_secret.authenticate(&salt_enc);
let hmac_secret_input = GetAssertionHmacSecretInput {
key_agreement: CoseKey::from_ecdh_public_key(platform_public_key),

View File

@@ -17,6 +17,7 @@ use crate::api::crypto::ecdh::{PublicKey as _, SecretKey as _, SharedSecret as _
use crate::api::crypto::hkdf256::Hkdf256;
use crate::api::crypto::hmac256::Hmac256;
use crate::api::crypto::sha256::Sha256;
use crate::api::rng::Rng;
use crate::ctap::client_pin::PIN_TOKEN_LENGTH;
use crate::ctap::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt};
use crate::ctap::data_formats::{CoseKey, PinUvAuthProtocol};
@@ -25,7 +26,6 @@ use crate::ctap::status_code::Ctap2StatusCode;
use crate::env::test::TestEnv;
use crate::env::{AesKey, EcdhPk, EcdhSk, Env, Hkdf, Hmac, Sha};
use alloc::vec::Vec;
use rng256::Rng256;
/// Implements common functions between existing PIN protocols for handshakes.
pub struct PinProtocol<E: Env> {
@@ -37,9 +37,9 @@ impl<E: Env> PinProtocol<E> {
/// This process is run by the authenticator at power-on.
///
/// This function implements "initialize" from the specification.
pub fn new(rng: &mut impl Rng256) -> Self {
let key_agreement_key = EcdhSk::<E>::random(rng);
let pin_uv_auth_token = rng.gen_uniform_u8x32();
pub fn new(env: &mut E) -> Self {
let key_agreement_key = EcdhSk::<E>::random(env.rng());
let pin_uv_auth_token = env.rng().gen_uniform_u8x32();
PinProtocol {
key_agreement_key,
pin_uv_auth_token,
@@ -47,13 +47,13 @@ impl<E: Env> PinProtocol<E> {
}
/// Generates a fresh public key.
pub fn regenerate(&mut self, rng: &mut impl Rng256) {
self.key_agreement_key = EcdhSk::<E>::random(rng);
pub fn regenerate(&mut self, env: &mut E) {
self.key_agreement_key = EcdhSk::<E>::random(env.rng());
}
/// Generates a fresh pinUvAuthToken.
pub fn reset_pin_uv_auth_token(&mut self, rng: &mut impl Rng256) {
self.pin_uv_auth_token = rng.gen_uniform_u8x32();
pub fn reset_pin_uv_auth_token(&mut self, env: &mut E) {
self.pin_uv_auth_token = env.rng().gen_uniform_u8x32();
}
/// Returns the authenticators public key as a CoseKey structure.
@@ -138,14 +138,10 @@ impl<E: Env> SharedSecret<E> {
}
/// Returns the encrypted plaintext.
pub fn encrypt(
&self,
rng: &mut dyn Rng256,
plaintext: &[u8],
) -> Result<Vec<u8>, Ctap2StatusCode> {
pub fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
match self {
SharedSecret::V1(s) => s.encrypt(rng, plaintext),
SharedSecret::V2(s) => s.encrypt(rng, plaintext),
SharedSecret::V1(s) => s.encrypt(env, plaintext),
SharedSecret::V2(s) => s.encrypt(env, plaintext),
}
}
@@ -221,8 +217,8 @@ impl<E: Env> SharedSecretV1<E> {
}
}
fn encrypt(&self, rng: &mut dyn Rng256, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
aes256_cbc_encrypt::<E>(rng, &self.aes_key, plaintext, false)
fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
aes256_cbc_encrypt(env, &self.aes_key, plaintext, false)
}
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
@@ -254,8 +250,8 @@ impl<E: Env> SharedSecretV2<E> {
}
}
fn encrypt(&self, rng: &mut dyn Rng256, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
aes256_cbc_encrypt::<E>(rng, &self.aes_key, plaintext, true)
fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
aes256_cbc_encrypt(env, &self.aes_key, plaintext, true)
}
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
@@ -280,9 +276,9 @@ mod test {
#[test]
fn test_pin_protocol_public_key() {
let mut env = TestEnv::default();
let mut pin_protocol = PinProtocol::<TestEnv>::new(env.rng());
let mut pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
let public_key = pin_protocol.get_public_key();
pin_protocol.regenerate(env.rng());
pin_protocol.regenerate(&mut env);
let new_public_key = pin_protocol.get_public_key();
assert_ne!(public_key, new_public_key);
}
@@ -290,9 +286,9 @@ mod test {
#[test]
fn test_pin_protocol_pin_uv_auth_token() {
let mut env = TestEnv::default();
let mut pin_protocol = PinProtocol::<TestEnv>::new(env.rng());
let mut pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
let token = *pin_protocol.get_pin_uv_auth_token();
pin_protocol.reset_pin_uv_auth_token(env.rng());
pin_protocol.reset_pin_uv_auth_token(&mut env);
let new_token = pin_protocol.get_pin_uv_auth_token();
assert_ne!(&token, new_token);
}
@@ -302,7 +298,7 @@ mod test {
let mut env = TestEnv::default();
let shared_secret = SharedSecretV1::<TestEnv>::new([0x55; 32]);
let plaintext = vec![0xAA; 64];
let ciphertext = shared_secret.encrypt(env.rng(), &plaintext).unwrap();
let ciphertext = shared_secret.encrypt(&mut env, &plaintext).unwrap();
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
}
@@ -338,7 +334,7 @@ mod test {
let mut env = TestEnv::default();
let shared_secret = SharedSecretV2::<TestEnv>::new([0x55; 32]);
let plaintext = vec![0xAA; 64];
let ciphertext = shared_secret.encrypt(env.rng(), &plaintext).unwrap();
let ciphertext = shared_secret.encrypt(&mut env, &plaintext).unwrap();
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
}
@@ -373,8 +369,8 @@ mod test {
#[test]
fn test_decapsulate_symmetric() {
let mut env = TestEnv::default();
let pin_protocol1 = PinProtocol::<TestEnv>::new(env.rng());
let pin_protocol2 = PinProtocol::<TestEnv>::new(env.rng());
let pin_protocol1 = PinProtocol::<TestEnv>::new(&mut env);
let pin_protocol2 = PinProtocol::<TestEnv>::new(&mut env);
for &protocol in &[PinUvAuthProtocol::V1, PinUvAuthProtocol::V2] {
let shared_secret1 = pin_protocol1
.decapsulate(pin_protocol2.get_public_key(), protocol)
@@ -383,7 +379,7 @@ mod test {
.decapsulate(pin_protocol1.get_public_key(), protocol)
.unwrap();
let plaintext = vec![0xAA; 64];
let ciphertext = shared_secret1.encrypt(env.rng(), &plaintext).unwrap();
let ciphertext = shared_secret1.encrypt(&mut env, &plaintext).unwrap();
assert_eq!(plaintext, shared_secret2.decrypt(&ciphertext).unwrap());
}
}

View File

@@ -17,6 +17,7 @@ mod key;
use crate::api::attestation_store::{self, AttestationStore};
use crate::api::customization::Customization;
use crate::api::key_store::KeyStore;
use crate::api::rng::Rng;
use crate::ctap::client_pin::PIN_AUTH_LENGTH;
use crate::ctap::data_formats::{
extract_array, extract_text_string, PublicKeyCredentialSource, PublicKeyCredentialUserEntity,
@@ -31,7 +32,6 @@ use arrayref::array_ref;
use core::cmp;
use core::convert::TryInto;
use persistent_store::{fragment, StoreUpdate};
use rng256::Rng256;
use sk_cbor::cbor_array_vec;
/// Wrapper for PIN properties.
@@ -626,7 +626,6 @@ mod test {
CredentialProtectionPolicy, PublicKeyCredentialSource, PublicKeyCredentialType,
};
use crate::env::test::TestEnv;
use rng256::Rng256;
fn create_credential_source(
env: &mut TestEnv,

View File

@@ -21,10 +21,10 @@ use crate::api::crypto::Crypto;
use crate::api::customization::Customization;
use crate::api::firmware_protection::FirmwareProtection;
use crate::api::key_store::KeyStore;
use crate::api::rng::Rng;
use crate::api::upgrade_storage::UpgradeStorage;
use crate::api::user_presence::UserPresence;
use persistent_store::{Storage, Store};
use rng256::Rng256;
#[cfg(feature = "std")]
pub mod test;
@@ -40,7 +40,7 @@ pub type Hkdf<E> = <<E as Env>::Crypto as Crypto>::Hkdf256;
/// Describes what CTAP needs to function.
pub trait Env {
type Rng: Rng256;
type Rng: Rng;
type UserPresence: UserPresence;
type Storage: Storage;
type KeyStore: KeyStore;

View File

@@ -19,20 +19,20 @@ use crate::api::connection::{HidConnection, SendOrRecvResult, SendOrRecvStatus};
use crate::api::crypto::software_crypto::SoftwareCrypto;
use crate::api::customization::DEFAULT_CUSTOMIZATION;
use crate::api::firmware_protection::FirmwareProtection;
use crate::api::rng::Rng;
use crate::api::user_presence::{UserPresence, UserPresenceResult};
use crate::api::{attestation_store, key_store};
use crate::env::Env;
use customization::TestCustomization;
use persistent_store::{BufferOptions, BufferStorage, Store};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use rng256::Rng256;
use rand::SeedableRng;
pub mod customization;
mod upgrade_storage;
pub struct TestEnv {
rng: TestRng256,
rng: TestRng,
user_presence: TestUserPresence,
store: Store<BufferStorage>,
upgrade_storage: Option<BufferUpgradeStorage>,
@@ -40,23 +40,9 @@ pub struct TestEnv {
clock: TestClock,
}
pub struct TestRng256 {
rng: StdRng,
}
pub type TestRng = StdRng;
impl TestRng256 {
pub fn seed_from_u64(&mut self, state: u64) {
self.rng = StdRng::seed_from_u64(state);
}
}
impl Rng256 for TestRng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut result = [Default::default(); 32];
self.rng.fill(&mut result);
result
}
}
impl Rng for TestRng {}
#[derive(Debug, Default, PartialEq)]
pub struct TestTimer {
@@ -131,9 +117,7 @@ impl HidConnection for TestEnv {
impl Default for TestEnv {
fn default() -> Self {
let rng = TestRng256 {
rng: StdRng::seed_from_u64(0),
};
let rng = StdRng::seed_from_u64(0);
let user_presence = TestUserPresence {
check: Box::new(|| Ok(())),
};
@@ -162,8 +146,8 @@ impl TestEnv {
&mut self.customization
}
pub fn rng(&mut self) -> &mut TestRng256 {
&mut self.rng
pub fn seed_rng_from_u64(&mut self, seed: u64) {
self.rng = StdRng::seed_from_u64(seed);
}
}
@@ -207,7 +191,7 @@ impl AttestationStore for TestEnv {
}
impl Env for TestEnv {
type Rng = TestRng256;
type Rng = TestRng;
type UserPresence = TestUserPresence;
type Storage = BufferStorage;
type KeyStore = Self;