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

@@ -1,39 +0,0 @@
---
name: RNG library tests
on:
push:
paths:
- 'libraries/rng256/**'
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'libraries/rng256/**'
jobs:
rng256_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Unit testing of rng256library (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/rng256/Cargo.toml --release --features std
- name: Unit testing of rng256 library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/rng256/Cargo.toml --features std

168
Cargo.lock generated
View File

@@ -17,15 +17,6 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -62,15 +53,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "crypto"
version = "0.1.0"
@@ -78,9 +60,9 @@ dependencies = [
"arrayref",
"byteorder",
"hex",
"rand_core",
"regex",
"ring",
"rng256",
"serde",
"serde_json",
"subtle",
@@ -102,8 +84,7 @@ dependencies = [
"opensk",
"openssl",
"persistent_store",
"rand 0.8.5",
"rng256",
"rand_core",
"sk-cbor",
"uuid",
]
@@ -149,12 +130,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "getrandom"
version = "0.2.7"
@@ -262,8 +237,8 @@ dependencies = [
"ed25519-compact",
"openssl",
"persistent_store",
"rand 0.8.5",
"rng256",
"rand",
"rand_core",
"sk-cbor",
"subtle",
"uuid",
@@ -301,7 +276,7 @@ version = "0.9.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"cc",
"libc",
"pkg-config",
@@ -320,9 +295,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
@@ -342,25 +317,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha 0.1.1",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand"
version = "0.8.5"
@@ -368,18 +324,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
"rand_chacha",
"rand_core",
]
[[package]]
@@ -389,24 +335,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.6.4"
@@ -416,77 +347,6 @@ dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "regex"
version = "1.6.0"
@@ -519,14 +379,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"rand 0.6.5",
]
[[package]]
name = "ryu"
version = "1.0.11"

View File

@@ -17,18 +17,17 @@ lang_items = { path = "third_party/lang-items" }
opensk = { path = "libraries/opensk" }
sk-cbor = { path = "libraries/cbor" }
crypto = { path = "libraries/crypto" }
rng256 = { path = "libraries/rng256" }
persistent_store = { path = "libraries/persistent_store" }
byteorder = { version = "1", default-features = false }
arrayref = "0.3.6"
rand = { version = "0.8.4", optional = true }
rand_core = "0.6.4"
ed25519-compact = { version = "1", default-features = false, optional = true }
[features]
debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap", "opensk/debug_ctap"]
panic_console = ["lang_items/panic_console"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand", "opensk/std"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "opensk/std"]
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
with_ctap1 = ["crypto/with_ctap1", "opensk/with_ctap1"]
with_nfc = ["libtock_drivers/with_nfc"]

View File

@@ -21,7 +21,7 @@ use alloc::format;
use alloc::vec::Vec;
use core::fmt::Write;
use crypto::{aes256, cbc, ecdsa, sha256, Hash256};
use ctap2::env::tock::TockRng256;
use ctap2::env::tock::TockRng;
use libtock_drivers::console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer;
@@ -36,7 +36,7 @@ fn main() {
let mut with_callback = timer::with_callback(|_, _| {});
let timer = with_callback.init().flex_unwrap();
let mut rng = TockRng256 {};
let mut rng = TockRng {};
writeln!(console, "****************************************").unwrap();
writeln!(

View File

@@ -10,7 +10,6 @@ license = "Apache-2.0"
edition = "2018"
[dependencies]
rng256 = { path = "../rng256" }
arrayref = "0.3.6"
subtle = { version = "2.2.3", default-features = false, features = ["nightly"] }
byteorder = { version = "1", default-features = false }
@@ -20,7 +19,8 @@ untrusted = { version = "0.7.0", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "=1.0.69", optional = true }
regex = { version = "1", optional = true }
rand_core = "0.6.4"
[features]
std = ["hex", "ring", "rng256/std", "untrusted", "serde", "serde_json", "regex"]
std = ["hex", "ring", "untrusted", "serde", "serde_json", "regex", "rand_core/getrandom"]
with_ctap1 = []

View File

@@ -14,7 +14,7 @@
use super::int256::{Digit, Int256};
use core::ops::Mul;
use rng256::Rng256;
use rand_core::RngCore;
use subtle::{self, Choice, ConditionallySelectable, CtOption};
// An exponent on the elliptic curve, that is an element modulo the curve order N.
@@ -112,7 +112,7 @@ impl NonZeroExponentP256 {
// Generates a uniformly distributed element 0 < k < N
pub fn gen_uniform<R>(r: &mut R) -> NonZeroExponentP256
where
R: Rng256,
R: RngCore,
{
loop {
let x = Int256::gen_uniform_256(r);
@@ -293,52 +293,4 @@ pub mod test {
assert_eq!(ONE.inv(), ONE);
assert_eq!(N_MIN_1.inv(), N_MIN_1);
}
/** RNG **/
// Mock rng that samples through a list of values, then panics.
struct StressTestingRng {
values: Vec<Int256>,
index: usize,
}
impl StressTestingRng {
pub fn new(values: Vec<Int256>) -> StressTestingRng {
StressTestingRng { values, index: 0 }
}
}
impl Rng256 for StressTestingRng {
// This function is unused, as we redefine gen_uniform_u32x8.
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
unreachable!()
}
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
let result = self.values[self.index].digits();
self.index += 1;
result
}
}
#[test]
fn test_uniform_non_zero_is_below_n() {
let mut rng = StressTestingRng::new(vec![
Int256::new([
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff,
]),
Int256::N,
N_MIN_1.to_int(),
Int256::N_MIN_2,
]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), N_MIN_1);
}
#[test]
fn test_uniform_n_is_above_zero() {
let mut rng = StressTestingRng::new(vec![Int256::ZERO]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), ONE);
}
}

View File

@@ -17,7 +17,7 @@ use alloc::vec::Vec;
use arrayref::{array_mut_ref, array_ref};
use byteorder::{BigEndian, ByteOrder};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use rng256::Rng256;
use rand_core::RngCore;
use subtle::{self, Choice, ConditionallySelectable, ConstantTimeEq};
const BITS_PER_DIGIT: usize = 32;
@@ -119,11 +119,13 @@ impl Int256 {
// Generates a uniformly distributed integer 0 <= x < 2^256
pub fn gen_uniform_256<R>(r: &mut R) -> Int256
where
R: Rng256,
R: RngCore,
{
Int256 {
digits: r.gen_uniform_u32x8(),
let mut digits = [0; NDIGITS];
for i in 0..NDIGITS {
digits[i] = r.next_u32();
}
Int256 { digits }
}
/** Serialization **/

View File

@@ -16,7 +16,7 @@ use super::ec::exponent256::NonZeroExponentP256;
use super::ec::int256;
use super::ec::int256::Int256;
use super::ec::point::PointP256;
use rng256::Rng256;
use rand_core::RngCore;
pub const NBYTES: usize = int256::NBYTES;
@@ -32,7 +32,7 @@ pub struct PubKey {
impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey
where
R: Rng256,
R: RngCore,
{
SecKey {
a: NonZeroExponentP256::gen_uniform(rng),
@@ -99,7 +99,7 @@ impl PubKey {
#[cfg(test)]
mod test {
use super::*;
use rng256::ThreadRng256;
use rand_core::OsRng;
// Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))]
@@ -110,7 +110,7 @@ mod test {
/** Test that key generation creates valid keys **/
#[test]
fn test_gen_pub_is_valid_random() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
@@ -122,7 +122,7 @@ mod test {
/** Test that the exchanged key is the same on both sides **/
#[test]
fn test_exchange_x_is_symmetric() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng);
@@ -135,7 +135,7 @@ mod test {
#[test]
fn test_exchange_x_bytes_is_symmetric() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng);

View File

@@ -24,7 +24,7 @@ use alloc::vec::Vec;
use arrayref::array_mut_ref;
use arrayref::{array_ref, mut_array_refs};
use core::marker::PhantomData;
use rng256::Rng256;
use rand_core::RngCore;
pub const NBYTES: usize = int256::NBYTES;
@@ -46,7 +46,7 @@ pub struct PubKey {
impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey
where
R: Rng256,
R: RngCore,
{
SecKey {
k: NonZeroExponentP256::gen_uniform(rng),
@@ -67,7 +67,7 @@ impl SecKey {
pub fn sign_rng<H, R>(&self, msg: &[u8], rng: &mut R) -> Signature
where
H: Hash256,
R: Rng256,
R: RngCore,
{
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
@@ -347,7 +347,7 @@ where
mod test {
use super::super::sha256::Sha256;
use super::*;
use rng256::ThreadRng256;
use rand_core::OsRng;
// Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))]
@@ -355,10 +355,16 @@ mod test {
#[cfg(debug_assertions)]
const ITERATIONS: u32 = 500;
fn gen_random_message(rng: &mut impl RngCore) -> [u8; 32] {
let mut bytes = [0; 32];
rng.fill_bytes(&mut bytes);
bytes
}
/** Test that key generation creates valid keys **/
#[test]
fn test_genpk_is_valid_random() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
@@ -370,7 +376,7 @@ mod test {
/** Serialization **/
#[test]
fn test_seckey_to_bytes_from_bytes() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
@@ -461,10 +467,10 @@ mod test {
// Test that signed message hashes are correctly verified.
#[test]
fn test_sign_rfc6979_verify_hash_random() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg);
@@ -476,10 +482,10 @@ mod test {
// Test that signed messages are correctly verified.
#[test]
fn test_sign_rfc6979_verify_random() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg);
@@ -490,10 +496,10 @@ mod test {
// Test that signed messages are correctly verified.
#[test]
fn test_sign_verify_random() {
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg, &mut rng);
@@ -578,10 +584,10 @@ mod test {
fn test_self_sign_ring_verify() {
use ring::signature::VerificationAlgorithm;
let mut rng = ThreadRng256 {};
let mut rng = OsRng::default();
for _ in 0..ITERATIONS {
let msg_bytes = rng.gen_uniform_u8x32();
let msg_bytes = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg_bytes, &mut rng);

View File

@@ -14,16 +14,15 @@ rust-version = "1.47"
[dependencies]
sk-cbor = { path = "../cbor" }
crypto = { path = "../crypto" }
rng256 = { path = "../rng256" }
persistent_store = { path = "../persistent_store" }
byteorder = { version = "1", default-features = false }
arrayref = "0.3.6"
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
arbitrary = { version = "0.4.7", features = ["derive"], optional = true }
rand = { version = "0.8.4", optional = true }
ed25519-compact = { version = "1", default-features = false, optional = true }
p256 = { version = "0.13.0", features = ["ecdh"], optional = true }
rand_core = { version = "0.6.4", optional = true }
rand_core = "0.6.4"
rand = { version = "0.8.5", optional = true }
sha2 = { version = "0.10.6", optional = true }
hmac = { version = "0.12.1", optional = true }
hkdf = { version = "0.12.3", optional = true }
@@ -32,12 +31,12 @@ cbc = { version = "0.1.2", optional = true }
[features]
debug_ctap = []
std = ["crypto/std", "persistent_store/std", "rng256/std", "rand"]
std = ["crypto/std", "persistent_store/std", "rand"]
with_ctap1 = ["crypto/with_ctap1"]
vendor_hid = []
fuzz = ["arbitrary", "std"]
ed25519 = ["ed25519-compact"]
rust_crypto = ["p256", "rand_core", "sha2", "hmac", "hkdf", "aes", "cbc"]
rust_crypto = ["p256", "sha2", "hmac", "hkdf", "aes", "cbc"]
[dev-dependencies]
enum-iterator = "0.6.0"

View File

@@ -9,6 +9,5 @@ edition = "2018"
arrayref = "0.3.6"
opensk = { path = "../..", features = ["fuzz"] }
crypto = { path = "../../../crypto", features = ['std'] }
rng256 = { path = "../../../rng256", features = ['std'] }
sk-cbor = { path = "../../../cbor" }
arbitrary = { version = "0.4.7", features = ["derive"] }

View File

@@ -137,7 +137,7 @@ pub fn process_ctap_any_type(data: &[u8]) -> arbitrary::Result<()> {
let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest();
// Initialize ctap state and hid and get the allocated cid.
@@ -184,7 +184,7 @@ pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitra
let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest();
if !is_type(data, input_type) {
@@ -218,7 +218,7 @@ pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult
let unstructured = &mut Unstructured::new(data);
let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(unstructured)?);
env.seed_rng_from_u64(u64::arbitrary(unstructured)?);
setup_customization(unstructured, env.customization_mut())?;
let mut state = CtapState::new(&mut env);
@@ -255,7 +255,7 @@ pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> {
let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest();
let message = raw_to_message(data);

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;

View File

@@ -1,17 +0,0 @@
[package]
name = "rng256"
version = "0.1.0"
authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>",
]
license = "Apache-2.0"
edition = "2018"
[dependencies]
arrayref = "0.3.6"
rand = { version = "0.6.5", optional = true }
[features]
std = ["rand"]

View File

@@ -1,82 +0,0 @@
// Copyright 2019-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_attr(not(feature = "std"), no_std)]
use arrayref::array_ref;
#[cfg(feature = "std")]
use rand::Rng;
// Lightweight RNG trait to generate uniformly distributed 256 bits.
pub trait Rng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32];
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
bytes_to_u32(self.gen_uniform_u8x32())
}
}
// The TockOS rng driver fills a buffer of bytes, but we need 32-bit words for ECDSA.
// This function does the conversion in safe Rust, using the native endianness to avoid unnecessary
// instructions.
// An unsafe one-line equivalent could be implemented with mem::transmute, but let's use safe Rust
// when possible.
fn bytes_to_u32(bytes: [u8; 32]) -> [u32; 8] {
let mut result: [u32; 8] = [Default::default(); 8];
for (i, r) in result.iter_mut().enumerate() {
*r = u32::from_ne_bytes(*array_ref![bytes, 4 * i, 4]);
}
result
}
// For tests on the desktop, we use the cryptographically secure thread rng as entropy source.
#[cfg(feature = "std")]
pub struct ThreadRng256 {}
#[cfg(feature = "std")]
impl Rng256 for ThreadRng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut rng = rand::thread_rng();
let mut result = [Default::default(); 32];
rng.fill(&mut result);
result
}
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
fn test_bytes_to_u32() {
// This tests that all bytes of the input are indeed used in the output, once each.
// Otherwise the result of gen_uniform_u32x8 wouldn't be uniformly distributed.
let bytes = b"\x00\x01\x02\x03\x04\x05\x06\x07\
\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
\x10\x11\x12\x13\x14\x15\x16\x17\
\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
#[cfg(target_endian = "big")]
let expected = [
0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617, 0x18191a1b,
0x1c1d1e1f,
];
#[cfg(target_endian = "little")]
let expected = [
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918,
0x1f1e1d1c,
];
assert_eq!(bytes_to_u32(*bytes), expected);
}
}

View File

@@ -26,9 +26,6 @@ cd ../..
cd libraries/crypto
cargo fmt -- --check
cd ../..
cd libraries/rng256
cargo fmt -- --check
cd ../..
cd libraries/persistent_store
cargo fmt -- --check
cd ../..
@@ -111,9 +108,6 @@ then
cd libraries/cbor
cargo test --release
cd ../..
cd libraries/rng256
cargo test --release --features std
cd ../..
cd libraries/persistent_store
cargo test --release --features std
cd ../..
@@ -124,9 +118,6 @@ then
cd libraries/cbor
cargo test
cd ../..
cd libraries/rng256
cargo test --features std
cd ../..
cd libraries/persistent_store
cargo test --features std
cd ../..

36
src/env/tock/mod.rs vendored
View File

@@ -30,11 +30,12 @@ use opensk::api::connection::{
use opensk::api::crypto::software_crypto::SoftwareCrypto;
use opensk::api::customization::{CustomizationImpl, AAGUID_LENGTH, DEFAULT_CUSTOMIZATION};
use opensk::api::firmware_protection::FirmwareProtection;
use opensk::api::rng::Rng;
use opensk::api::user_presence::{UserPresence, UserPresenceError, UserPresenceResult};
use opensk::api::{attestation_store, key_store};
use opensk::env::Env;
use persistent_store::{StorageResult, Store};
use rng256::Rng256;
use rand_core::{impls, CryptoRng, Error, RngCore};
mod clock;
mod storage;
@@ -48,16 +49,31 @@ const TOCK_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
};
/// RNG backed by the TockOS rng driver.
pub struct TockRng256 {}
pub struct TockRng {}
impl Rng256 for TockRng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut buf: [u8; 32] = [Default::default(); 32];
rng::fill_buffer(&mut buf);
buf
impl CryptoRng for TockRng {}
impl RngCore for TockRng {
fn next_u32(&mut self) -> u32 {
impls::next_u32_via_fill(self)
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_fill(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rng::fill_buffer(dest);
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl Rng for TockRng {}
pub struct TockHidConnection {
endpoint: UsbEndpoint,
}
@@ -80,7 +96,7 @@ impl HidConnection for TockHidConnection {
}
pub struct TockEnv {
rng: TockRng256,
rng: TockRng,
store: Store<TockStorage>,
upgrade_storage: Option<TockUpgradeStorage>,
main_connection: TockHidConnection,
@@ -102,7 +118,7 @@ impl Default for TockEnv {
let store = Store::new(storage).ok().unwrap();
let upgrade_storage = TockUpgradeStorage::new().ok();
TockEnv {
rng: TockRng256 {},
rng: TockRng {},
store,
upgrade_storage,
main_connection: TockHidConnection {
@@ -239,7 +255,7 @@ impl AttestationStore for TockEnv {
}
impl Env for TockEnv {
type Rng = TockRng256;
type Rng = TockRng;
type UserPresence = Self;
type Storage = TockStorage;
type KeyStore = Self;