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:
39
.github/workflows/rng256_test.yml
vendored
39
.github/workflows/rng256_test.yml
vendored
@@ -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
168
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 **/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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;
|
||||
|
||||
30
libraries/opensk/src/api/rng.rs
Normal file
30
libraries/opensk/src/api/rng.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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[..],
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 authenticator’s 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
4
libraries/opensk/src/env/mod.rs
vendored
4
libraries/opensk/src/env/mod.rs
vendored
@@ -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;
|
||||
|
||||
34
libraries/opensk/src/env/test/mod.rs
vendored
34
libraries/opensk/src/env/test/mod.rs
vendored
@@ -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;
|
||||
|
||||
@@ -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"]
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
36
src/env/tock/mod.rs
vendored
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user