Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b7a3961

Browse files
committedNov 26, 2023
provide a cryptoki-backed CSPRNG
Signed-off-by: Arthur Gautier <[email protected]>
1 parent ccba914 commit b7a3961

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed
 

‎cryptoki-rustcrypto/src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use cryptoki::{
99
};
1010

1111
pub mod ecdsa;
12+
pub mod rng;
1213
pub mod rsa;
1314
pub mod x509;
1415

@@ -21,6 +22,7 @@ pub trait SessionLike {
2122
attributes: &[AttributeType],
2223
) -> Result<Vec<Attribute>>;
2324
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>>;
25+
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()>;
2426
}
2527

2628
impl SessionLike for Session {
@@ -40,6 +42,9 @@ impl SessionLike for Session {
4042
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
4143
Session::sign(self, mechanism, key, data)
4244
}
45+
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> {
46+
Session::generate_random_slice(self, random_data)
47+
}
4348
}
4449

4550
impl<'s> SessionLike for &'s Session {
@@ -59,4 +64,7 @@ impl<'s> SessionLike for &'s Session {
5964
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
6065
Session::sign(self, mechanism, key, data)
6166
}
67+
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> {
68+
Session::generate_random_slice(self, random_data)
69+
}
6270
}

‎cryptoki-rustcrypto/src/rng.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2023 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use signature::rand_core::{CryptoRng, Error as RndError, RngCore};
5+
use thiserror::Error;
6+
7+
use crate::SessionLike;
8+
9+
#[derive(Debug, Error)]
10+
pub enum Error {}
11+
12+
/// [`CryptokiRng`] is a PKCS#11-backed CSPRNG.
13+
pub struct Rng<S: SessionLike>(S);
14+
15+
// TODO(baloo): check for CKF_RNG bit flag (CK_TOKEN_INFO struct -> flags)
16+
impl<S: SessionLike> Rng<S> {
17+
pub fn new(session: S) -> Result<Self, Error> {
18+
Ok(Self(session))
19+
}
20+
}
21+
22+
macro_rules! impl_next_uint {
23+
($self:ident, $u:ty) => {{
24+
let mut buf = <$u>::MIN.to_be_bytes();
25+
$self.fill_bytes(&mut buf[..]);
26+
27+
<$u>::from_be_bytes(buf)
28+
}};
29+
}
30+
31+
impl<S: SessionLike> RngCore for Rng<S> {
32+
fn next_u32(&mut self) -> u32 {
33+
impl_next_uint!(self, u32)
34+
}
35+
36+
fn next_u64(&mut self) -> u64 {
37+
impl_next_uint!(self, u64)
38+
}
39+
40+
fn fill_bytes(&mut self, dest: &mut [u8]) {
41+
self.try_fill_bytes(dest)
42+
.expect("Cryptoki provider failed to generate random");
43+
}
44+
45+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RndError> {
46+
self.0.generate_random_slice(dest).map_err(RndError::new)
47+
}
48+
}
49+
50+
impl<S: SessionLike> CryptoRng for Rng<S> {}

‎cryptoki-rustcrypto/tests/rng.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2023 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
mod common;
5+
6+
use crate::common::USER_PIN;
7+
use common::init_pins;
8+
use cryptoki::{session::UserType, types::AuthPin};
9+
use cryptoki_rustcrypto::rng::Rng;
10+
use serial_test::serial;
11+
use signature::rand_core::{CryptoRngCore, RngCore};
12+
use testresult::TestResult;
13+
14+
// This test is meant to ensure we provide [`rand_core::CryptoRngCore`].
15+
// This is the trait consumers will use throughout the RustCrypto ecosystem
16+
// to express interest in a CSPRNG.
17+
#[test]
18+
#[serial]
19+
fn ensure_crypto_rng_core() -> TestResult {
20+
fn just_making_sure<R: CryptoRngCore>(_r: &mut R) {
21+
// Hi! just making sure you provide a CSPRNG.
22+
}
23+
let (pkcs11, slot) = init_pins();
24+
25+
// open a session
26+
let session = pkcs11.open_rw_session(slot)?;
27+
28+
// log in the session
29+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
30+
31+
let mut rng = Rng::new(session).unwrap();
32+
just_making_sure(&mut rng);
33+
34+
Ok(())
35+
}
36+
37+
#[test]
38+
#[serial]
39+
fn generate_random() -> TestResult {
40+
let (pkcs11, slot) = init_pins();
41+
42+
// open a session
43+
let session = pkcs11.open_rw_session(slot)?;
44+
45+
// log in the session
46+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
47+
48+
let mut rng = Rng::new(session).unwrap();
49+
rng.next_u32();
50+
rng.next_u64();
51+
52+
let mut buf = vec![0; 123];
53+
rng.fill_bytes(&mut buf);
54+
rng.try_fill_bytes(&mut buf).unwrap();
55+
56+
Ok(())
57+
}

0 commit comments

Comments
 (0)
Please sign in to comment.