Adds AES256 to the Crypto trait (#611)
This commit is contained in:
@@ -27,6 +27,8 @@ rand_core = { version = "0.6.4", optional = true }
|
||||
sha2 = { version = "0.10.6", optional = true }
|
||||
hmac = { version = "0.12.1", optional = true }
|
||||
hkdf = { version = "0.12.3", optional = true }
|
||||
aes = { version = "0.8.2", optional = true }
|
||||
cbc = { version = "0.1.2", optional = true }
|
||||
|
||||
[features]
|
||||
debug_ctap = []
|
||||
@@ -35,7 +37,7 @@ with_ctap1 = ["crypto/with_ctap1"]
|
||||
vendor_hid = []
|
||||
fuzz = ["arbitrary", "std"]
|
||||
ed25519 = ["ed25519-compact"]
|
||||
rust_crypto = ["p256", "rand_core", "sha2", "hmac", "hkdf"]
|
||||
rust_crypto = ["p256", "rand_core", "sha2", "hmac", "hkdf", "aes", "cbc"]
|
||||
|
||||
[dev-dependencies]
|
||||
enum-iterator = "0.6.0"
|
||||
|
||||
41
libraries/opensk/src/api/crypto/aes256.rs
Normal file
41
libraries/opensk/src/api/crypto/aes256.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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 super::{AES_BLOCK_SIZE, AES_KEY_SIZE};
|
||||
|
||||
/// Encrypts and decrypts data using AES256.
|
||||
pub trait Aes256 {
|
||||
/// Creates a new key from its bytes.
|
||||
fn new(key: &[u8; AES_KEY_SIZE]) -> Self;
|
||||
|
||||
/// Encrypts a block in place.
|
||||
fn encrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]);
|
||||
|
||||
/// Decrypts a block in place.
|
||||
fn decrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]);
|
||||
|
||||
/// Encrypts a message in place using CBC mode.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the plaintext is not a multiple of the block size.
|
||||
fn encrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], plaintext: &mut [u8]);
|
||||
|
||||
/// Decrypts a message in place using CBC mode.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the ciphertext is not a multiple of the block size.
|
||||
fn decrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], ciphertext: &mut [u8]);
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod aes256;
|
||||
pub mod ecdh;
|
||||
pub mod ecdsa;
|
||||
#[cfg(feature = "rust_crypto")]
|
||||
@@ -24,12 +25,19 @@ pub mod hkdf256;
|
||||
pub mod hmac256;
|
||||
pub mod sha256;
|
||||
|
||||
use self::aes256::Aes256;
|
||||
use self::ecdh::Ecdh;
|
||||
use self::ecdsa::Ecdsa;
|
||||
use self::hkdf256::Hkdf256;
|
||||
use self::hmac256::Hmac256;
|
||||
use self::sha256::Sha256;
|
||||
|
||||
/// The size of a serialized ECDSA signature.
|
||||
pub const AES_BLOCK_SIZE: usize = 16;
|
||||
|
||||
/// The size of field elements in the elliptic curve P256.
|
||||
pub const AES_KEY_SIZE: usize = 32;
|
||||
|
||||
/// The size of field elements in the elliptic curve P256.
|
||||
pub const EC_FIELD_SIZE: usize = 32;
|
||||
|
||||
@@ -49,9 +57,140 @@ pub const TRUNCATED_HMAC_SIZE: usize = 16;
|
||||
|
||||
/// Necessary cryptographic primitives for CTAP.
|
||||
pub trait Crypto {
|
||||
type Aes256: Aes256;
|
||||
type Ecdh: Ecdh;
|
||||
type Ecdsa: Ecdsa;
|
||||
type Sha256: Sha256;
|
||||
type Hmac256: Hmac256;
|
||||
type Hkdf256: Hkdf256;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::software_crypto::*;
|
||||
use super::*;
|
||||
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 core::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_shared_secret_symmetric() {
|
||||
let mut env = TestEnv::default();
|
||||
let private1 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let private2 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let pub1 = private1.public_key();
|
||||
let pub2 = private2.public_key();
|
||||
let shared1 = private1.diffie_hellman(&pub2);
|
||||
let shared2 = private2.diffie_hellman(&pub1);
|
||||
assert_eq!(shared1.raw_secret_bytes(), shared2.raw_secret_bytes());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdh_public_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let first_public = first_key.public_key();
|
||||
let mut x = [0; EC_FIELD_SIZE];
|
||||
let mut y = [0; EC_FIELD_SIZE];
|
||||
first_public.to_coordinates(&mut x, &mut y);
|
||||
let new_public = SoftwareEcdhPublicKey::from_coordinates(&x, &y).unwrap();
|
||||
let mut new_x = [0; EC_FIELD_SIZE];
|
||||
let mut new_y = [0; EC_FIELD_SIZE];
|
||||
new_public.to_coordinates(&mut new_x, &mut new_y);
|
||||
assert_eq!(x, new_x);
|
||||
assert_eq!(y, new_y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sign_verify() {
|
||||
let mut env = TestEnv::default();
|
||||
let private_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let public_key = private_key.public_key();
|
||||
let message = [0x12, 0x34, 0x56, 0x78];
|
||||
let signature = private_key.sign(&message);
|
||||
assert!(public_key.verify(&message, &signature));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdsa_secret_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let mut key_bytes = [0; EC_FIELD_SIZE];
|
||||
first_key.to_slice(&mut key_bytes);
|
||||
let second_key = SoftwareEcdsaSecretKey::from_slice(&key_bytes).unwrap();
|
||||
let mut new_bytes = [0; EC_FIELD_SIZE];
|
||||
second_key.to_slice(&mut new_bytes);
|
||||
assert_eq!(key_bytes, new_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_hash_matches() {
|
||||
let data = [0x55; 16];
|
||||
let mut hasher = SoftwareSha256::new();
|
||||
hasher.update(&data);
|
||||
assert_eq!(SoftwareSha256::digest(&data), hasher.finalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac256_verifies() {
|
||||
let key = [0xAA; HMAC_KEY_SIZE];
|
||||
let data = [0x55; 16];
|
||||
let mac = SoftwareHmac256::mac(&key, &data);
|
||||
assert!(SoftwareHmac256::verify(&key, &data, &mac));
|
||||
let truncated_mac =
|
||||
<&[u8; TRUNCATED_HMAC_SIZE]>::try_from(&mac[..TRUNCATED_HMAC_SIZE]).unwrap();
|
||||
assert!(SoftwareHmac256::verify_truncated_left(
|
||||
&key,
|
||||
&data,
|
||||
&truncated_mac
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hkdf_empty_salt_256_vector() {
|
||||
let okm = [
|
||||
0xf9, 0xbe, 0x72, 0x11, 0x6c, 0xb9, 0x7f, 0x41, 0x82, 0x82, 0x10, 0x28, 0x9c, 0xaa,
|
||||
0xfe, 0xab, 0xde, 0x1f, 0x3d, 0xfb, 0x97, 0x23, 0xbf, 0x43, 0x53, 0x8a, 0xb1, 0x8f,
|
||||
0x36, 0x66, 0x78, 0x3a,
|
||||
];
|
||||
assert_eq!(&SoftwareHkdf256::hkdf_empty_salt_256(b"0", &[0]), &okm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_encrypt_decrypt_block() {
|
||||
let mut block = [0x55; AES_BLOCK_SIZE];
|
||||
let aes = SoftwareAes256::new(&[0xAA; AES_KEY_SIZE]);
|
||||
aes.encrypt_block(&mut block);
|
||||
aes.decrypt_block(&mut block);
|
||||
assert_eq!(block, [0x55; AES_BLOCK_SIZE]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_encrypt_decrypt_cbc() {
|
||||
let mut message = [0x55; 2 * AES_BLOCK_SIZE];
|
||||
let iv = [0x11; AES_BLOCK_SIZE];
|
||||
let aes = SoftwareAes256::new(&[0xAA; AES_KEY_SIZE]);
|
||||
aes.encrypt_cbc(&iv, &mut message);
|
||||
aes.decrypt_cbc(&iv, &mut message);
|
||||
assert_eq!(message, [0x55; 2 * AES_BLOCK_SIZE]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_aes_encrypt_panics() {
|
||||
let mut message = [0x55; AES_BLOCK_SIZE + 1];
|
||||
let iv = [0x11; AES_BLOCK_SIZE];
|
||||
let aes = SoftwareAes256::new(&[0xAA; AES_KEY_SIZE]);
|
||||
aes.encrypt_cbc(&iv, &mut message);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_aes_decrypt_panics() {
|
||||
let mut message = [0x55; AES_BLOCK_SIZE + 1];
|
||||
let iv = [0x11; AES_BLOCK_SIZE];
|
||||
let aes = SoftwareAes256::new(&[0xAA; AES_KEY_SIZE]);
|
||||
aes.decrypt_cbc(&iv, &mut message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,17 @@
|
||||
//!
|
||||
//! If you want to use OpenSK outside of Tock v1, maybe this is useful for you though!
|
||||
|
||||
use crate::api::crypto::aes256::Aes256;
|
||||
use crate::api::crypto::hkdf256::Hkdf256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
use crate::api::crypto::sha256::Sha256;
|
||||
use crate::api::crypto::{
|
||||
ecdh, ecdsa, Crypto, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE, HMAC_KEY_SIZE,
|
||||
TRUNCATED_HMAC_SIZE,
|
||||
ecdh, ecdsa, Crypto, AES_BLOCK_SIZE, AES_KEY_SIZE, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE,
|
||||
HMAC_KEY_SIZE, TRUNCATED_HMAC_SIZE,
|
||||
};
|
||||
use aes::cipher::generic_array::GenericArray;
|
||||
use aes::cipher::{
|
||||
BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut, KeyInit, KeyIvInit,
|
||||
};
|
||||
use core::convert::TryFrom;
|
||||
use hmac::Mac;
|
||||
@@ -43,6 +48,7 @@ pub struct SoftwareEcdh;
|
||||
pub struct SoftwareEcdsa;
|
||||
|
||||
impl Crypto for SoftwareCrypto {
|
||||
type Aes256 = SoftwareAes256;
|
||||
type Ecdh = SoftwareEcdh;
|
||||
type Ecdsa = SoftwareEcdsa;
|
||||
type Sha256 = SoftwareSha256;
|
||||
@@ -228,13 +234,13 @@ pub struct SoftwareHmac256;
|
||||
|
||||
impl Hmac256 for SoftwareHmac256 {
|
||||
fn mac(key: &[u8; HMAC_KEY_SIZE], data: &[u8]) -> [u8; HASH_SIZE] {
|
||||
let mut hmac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key).unwrap();
|
||||
let mut hmac = <hmac::Hmac<sha2::Sha256> as hmac::Mac>::new_from_slice(key).unwrap();
|
||||
hmac.update(data);
|
||||
hmac.finalize().into_bytes().into()
|
||||
}
|
||||
|
||||
fn verify(key: &[u8; HMAC_KEY_SIZE], data: &[u8], mac: &[u8; HASH_SIZE]) -> bool {
|
||||
let mut hmac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key).unwrap();
|
||||
let mut hmac = <hmac::Hmac<sha2::Sha256> as hmac::Mac>::new_from_slice(key).unwrap();
|
||||
hmac.update(data);
|
||||
hmac.verify_slice(mac).is_ok()
|
||||
}
|
||||
@@ -244,7 +250,7 @@ impl Hmac256 for SoftwareHmac256 {
|
||||
data: &[u8],
|
||||
mac: &[u8; TRUNCATED_HMAC_SIZE],
|
||||
) -> bool {
|
||||
let mut hmac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key).unwrap();
|
||||
let mut hmac = <hmac::Hmac<sha2::Sha256> as hmac::Mac>::new_from_slice(key).unwrap();
|
||||
hmac.update(data);
|
||||
hmac.verify_truncated_left(mac).is_ok()
|
||||
}
|
||||
@@ -261,95 +267,36 @@ impl Hkdf256 for SoftwareHkdf256 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::api::crypto::ecdh::{
|
||||
PublicKey as EcdhPublicKey, SecretKey as EcdhSecretKey, SharedSecret,
|
||||
};
|
||||
use crate::api::crypto::ecdsa::{PublicKey as EcdsaPublicKey, SecretKey as EcdsaSecretKey};
|
||||
use crate::env::test::TestEnv;
|
||||
pub struct SoftwareAes256 {
|
||||
key: [u8; AES_KEY_SIZE],
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shared_secret_symmetric() {
|
||||
let mut env = TestEnv::default();
|
||||
let private1 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let private2 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let pub1 = private1.public_key();
|
||||
let pub2 = private2.public_key();
|
||||
let shared1 = private1.diffie_hellman(&pub2);
|
||||
let shared2 = private2.diffie_hellman(&pub1);
|
||||
assert_eq!(shared1.raw_secret_bytes(), shared2.raw_secret_bytes());
|
||||
impl Aes256 for SoftwareAes256 {
|
||||
fn new(key: &[u8; AES_KEY_SIZE]) -> Self {
|
||||
SoftwareAes256 { key: key.clone() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdh_public_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let first_public = first_key.public_key();
|
||||
let mut x = [0; EC_FIELD_SIZE];
|
||||
let mut y = [0; EC_FIELD_SIZE];
|
||||
first_public.to_coordinates(&mut x, &mut y);
|
||||
let new_public = SoftwareEcdhPublicKey::from_coordinates(&x, &y).unwrap();
|
||||
let mut new_x = [0; EC_FIELD_SIZE];
|
||||
let mut new_y = [0; EC_FIELD_SIZE];
|
||||
new_public.to_coordinates(&mut new_x, &mut new_y);
|
||||
assert_eq!(x, new_x);
|
||||
assert_eq!(y, new_y);
|
||||
fn encrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]) {
|
||||
let cipher = aes::Aes256::new_from_slice(&self.key).unwrap();
|
||||
cipher.encrypt_block(block.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sign_verify() {
|
||||
let mut env = TestEnv::default();
|
||||
let private_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let public_key = private_key.public_key();
|
||||
let message = [0x12, 0x34, 0x56, 0x78];
|
||||
let signature = private_key.sign(&message);
|
||||
assert!(public_key.verify(&message, &signature));
|
||||
fn decrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]) {
|
||||
let cipher = aes::Aes256::new_from_slice(&self.key).unwrap();
|
||||
cipher.decrypt_block(block.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdsa_secret_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let mut key_bytes = [0; EC_FIELD_SIZE];
|
||||
first_key.to_slice(&mut key_bytes);
|
||||
let second_key = SoftwareEcdsaSecretKey::from_slice(&key_bytes).unwrap();
|
||||
let mut new_bytes = [0; EC_FIELD_SIZE];
|
||||
second_key.to_slice(&mut new_bytes);
|
||||
assert_eq!(key_bytes, new_bytes);
|
||||
fn encrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], plaintext: &mut [u8]) {
|
||||
let mut encryptor = cbc::Encryptor::<aes::Aes256>::new_from_slices(&self.key, iv).unwrap();
|
||||
for block in plaintext.chunks_mut(AES_BLOCK_SIZE) {
|
||||
encryptor.encrypt_block_mut(GenericArray::from_mut_slice(block));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_hash_matches() {
|
||||
let data = [0x55; 16];
|
||||
let mut hasher = SoftwareSha256::new();
|
||||
hasher.update(&data);
|
||||
assert_eq!(SoftwareSha256::digest(&data), hasher.finalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac256_verifies() {
|
||||
let key = [0xAA; HMAC_KEY_SIZE];
|
||||
let data = [0x55; 16];
|
||||
let mac = SoftwareHmac256::mac(&key, &data);
|
||||
assert!(SoftwareHmac256::verify(&key, &data, &mac));
|
||||
let truncated_mac =
|
||||
<&[u8; TRUNCATED_HMAC_SIZE]>::try_from(&mac[..TRUNCATED_HMAC_SIZE]).unwrap();
|
||||
assert!(SoftwareHmac256::verify_truncated_left(
|
||||
&key,
|
||||
&data,
|
||||
&truncated_mac
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hkdf_empty_salt_256_vector() {
|
||||
let okm = [
|
||||
0xf9, 0xbe, 0x72, 0x11, 0x6c, 0xb9, 0x7f, 0x41, 0x82, 0x82, 0x10, 0x28, 0x9c, 0xaa,
|
||||
0xfe, 0xab, 0xde, 0x1f, 0x3d, 0xfb, 0x97, 0x23, 0xbf, 0x43, 0x53, 0x8a, 0xb1, 0x8f,
|
||||
0x36, 0x66, 0x78, 0x3a,
|
||||
];
|
||||
assert_eq!(&SoftwareHkdf256::hkdf_empty_salt_256(b"0", &[0]), &okm);
|
||||
fn decrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], ciphertext: &mut [u8]) {
|
||||
let mut decryptor = cbc::Decryptor::<aes::Aes256>::new_from_slices(&self.key, iv).unwrap();
|
||||
for block in ciphertext.chunks_mut(AES_BLOCK_SIZE) {
|
||||
decryptor.decrypt_block_mut(GenericArray::from_mut_slice(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::api::crypto::aes256::Aes256;
|
||||
use crate::api::crypto::hkdf256::Hkdf256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
use crate::api::crypto::sha256::Sha256;
|
||||
use crate::api::crypto::{
|
||||
ecdh, ecdsa, Crypto, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE, HMAC_KEY_SIZE,
|
||||
TRUNCATED_HMAC_SIZE,
|
||||
ecdh, ecdsa, Crypto, AES_BLOCK_SIZE, AES_KEY_SIZE, EC_FIELD_SIZE, EC_SIGNATURE_SIZE, HASH_SIZE,
|
||||
HMAC_KEY_SIZE, TRUNCATED_HMAC_SIZE,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use crypto::Hash256;
|
||||
@@ -28,6 +29,7 @@ pub struct SoftwareEcdh;
|
||||
pub struct SoftwareEcdsa;
|
||||
|
||||
impl Crypto for SoftwareCrypto {
|
||||
type Aes256 = SoftwareAes256;
|
||||
type Ecdh = SoftwareEcdh;
|
||||
type Ecdsa = SoftwareEcdsa;
|
||||
type Sha256 = SoftwareSha256;
|
||||
@@ -211,96 +213,31 @@ impl Hkdf256 for SoftwareHkdf256 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::api::crypto::ecdh::{
|
||||
PublicKey as EcdhPublicKey, SecretKey as EcdhSecretKey, SharedSecret,
|
||||
};
|
||||
use crate::api::crypto::ecdsa::{PublicKey as EcdsaPublicKey, SecretKey as EcdsaSecretKey};
|
||||
use crate::env::test::TestEnv;
|
||||
use core::convert::TryFrom;
|
||||
pub struct SoftwareAes256 {
|
||||
enc_key: crypto::aes256::EncryptionKey,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shared_secret_symmetric() {
|
||||
let mut env = TestEnv::default();
|
||||
let private1 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let private2 = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let pub1 = private1.public_key();
|
||||
let pub2 = private2.public_key();
|
||||
let shared1 = private1.diffie_hellman(&pub2);
|
||||
let shared2 = private2.diffie_hellman(&pub1);
|
||||
assert_eq!(shared1.raw_secret_bytes(), shared2.raw_secret_bytes());
|
||||
impl Aes256 for SoftwareAes256 {
|
||||
fn new(key: &[u8; AES_KEY_SIZE]) -> Self {
|
||||
let enc_key = crypto::aes256::EncryptionKey::new(key);
|
||||
SoftwareAes256 { enc_key }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdh_public_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdhSecretKey::random(env.rng());
|
||||
let first_public = first_key.public_key();
|
||||
let mut x = [0; EC_FIELD_SIZE];
|
||||
let mut y = [0; EC_FIELD_SIZE];
|
||||
first_public.to_coordinates(&mut x, &mut y);
|
||||
let new_public = SoftwareEcdhPublicKey::from_coordinates(&x, &y).unwrap();
|
||||
let mut new_x = [0; EC_FIELD_SIZE];
|
||||
let mut new_y = [0; EC_FIELD_SIZE];
|
||||
new_public.to_coordinates(&mut new_x, &mut new_y);
|
||||
assert_eq!(x, new_x);
|
||||
assert_eq!(y, new_y);
|
||||
fn encrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]) {
|
||||
self.enc_key.encrypt_block(block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sign_verify() {
|
||||
let mut env = TestEnv::default();
|
||||
let private_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let public_key = private_key.public_key();
|
||||
let message = [0x12, 0x34, 0x56, 0x78];
|
||||
let signature = private_key.sign(&message);
|
||||
assert!(public_key.verify(&message, &signature));
|
||||
fn decrypt_block(&self, block: &mut [u8; AES_BLOCK_SIZE]) {
|
||||
let dec_key = crypto::aes256::DecryptionKey::new(&self.enc_key);
|
||||
dec_key.decrypt_block(block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecdsa_secret_key_from_to_bytes() {
|
||||
let mut env = TestEnv::default();
|
||||
let first_key = SoftwareEcdsaSecretKey::random(env.rng());
|
||||
let mut key_bytes = [0; EC_FIELD_SIZE];
|
||||
first_key.to_slice(&mut key_bytes);
|
||||
let second_key = SoftwareEcdsaSecretKey::from_slice(&key_bytes).unwrap();
|
||||
let mut new_bytes = [0; EC_FIELD_SIZE];
|
||||
second_key.to_slice(&mut new_bytes);
|
||||
assert_eq!(key_bytes, new_bytes);
|
||||
fn encrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], plaintext: &mut [u8]) {
|
||||
crypto::cbc::cbc_encrypt(&self.enc_key, *iv, plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_hash_matches() {
|
||||
let data = [0x55; 16];
|
||||
let mut hasher = SoftwareSha256::new();
|
||||
hasher.update(&data);
|
||||
assert_eq!(SoftwareSha256::digest(&data), hasher.finalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac256_verifies() {
|
||||
let key = [0xAA; HMAC_KEY_SIZE];
|
||||
let data = [0x55; 16];
|
||||
let mac = SoftwareHmac256::mac(&key, &data);
|
||||
assert!(SoftwareHmac256::verify(&key, &data, &mac));
|
||||
let truncated_mac =
|
||||
<&[u8; TRUNCATED_HMAC_SIZE]>::try_from(&mac[..TRUNCATED_HMAC_SIZE]).unwrap();
|
||||
assert!(SoftwareHmac256::verify_truncated_left(
|
||||
&key,
|
||||
&data,
|
||||
truncated_mac
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hkdf_empty_salt_256_vector() {
|
||||
let okm = [
|
||||
0xf9, 0xbe, 0x72, 0x11, 0x6c, 0xb9, 0x7f, 0x41, 0x82, 0x82, 0x10, 0x28, 0x9c, 0xaa,
|
||||
0xfe, 0xab, 0xde, 0x1f, 0x3d, 0xfb, 0x97, 0x23, 0xbf, 0x43, 0x53, 0x8a, 0xb1, 0x8f,
|
||||
0x36, 0x66, 0x78, 0x3a,
|
||||
];
|
||||
assert_eq!(&SoftwareHkdf256::hkdf_empty_salt_256(b"0", &[0]), &okm);
|
||||
fn decrypt_cbc(&self, iv: &[u8; AES_BLOCK_SIZE], ciphertext: &mut [u8]) {
|
||||
let dec_key = crypto::aes256::DecryptionKey::new(&self.enc_key);
|
||||
crypto::cbc::cbc_decrypt(&dec_key, *iv, ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@ use super::data_formats::{
|
||||
};
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::{cbor_read, cbor_write};
|
||||
use crate::api::crypto::aes256::Aes256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
use crate::api::key_store::KeyStore;
|
||||
use crate::ctap::data_formats::{extract_byte_string, extract_map};
|
||||
use crate::env::{Env, Hmac};
|
||||
use crate::env::{AesKey, Env, Hmac};
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
@@ -64,12 +65,12 @@ impl From<CredentialSourceField> for sk_cbor::Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt_legacy_credential_id(
|
||||
env: &mut impl Env,
|
||||
fn decrypt_legacy_credential_id<E: Env>(
|
||||
env: &mut E,
|
||||
bytes: &[u8],
|
||||
) -> Result<Option<CredentialSource>, Ctap2StatusCode> {
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
|
||||
let plaintext = aes256_cbc_decrypt(&aes_enc_key, bytes, true)?;
|
||||
let aes_key = AesKey::<E>::new(&env.key_store().key_handle_encryption()?);
|
||||
let plaintext = aes256_cbc_decrypt::<E>(&aes_key, bytes, true)?;
|
||||
if plaintext.len() != 64 {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -86,12 +87,12 @@ fn decrypt_legacy_credential_id(
|
||||
}))
|
||||
}
|
||||
|
||||
fn decrypt_cbor_credential_id(
|
||||
env: &mut impl Env,
|
||||
fn decrypt_cbor_credential_id<E: Env>(
|
||||
env: &mut E,
|
||||
bytes: &[u8],
|
||||
) -> Result<Option<CredentialSource>, Ctap2StatusCode> {
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
|
||||
let mut plaintext = aes256_cbc_decrypt(&aes_enc_key, bytes, true)?;
|
||||
let aes_key = AesKey::<E>::new(&env.key_store().key_handle_encryption()?);
|
||||
let mut plaintext = aes256_cbc_decrypt::<E>(&aes_key, bytes, true)?;
|
||||
remove_padding(&mut plaintext)?;
|
||||
|
||||
let cbor_credential_source = cbor_read(plaintext.as_slice())?;
|
||||
@@ -177,8 +178,8 @@ pub fn encrypt_to_credential_id<E: Env>(
|
||||
cbor_write(cbor, &mut payload)?;
|
||||
add_padding(&mut payload)?;
|
||||
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
|
||||
let encrypted_payload = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &payload, true)?;
|
||||
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 mut credential_id = encrypted_payload;
|
||||
credential_id.insert(0, CBOR_CREDENTIAL_ID_VERSION);
|
||||
|
||||
@@ -383,13 +384,13 @@ mod test {
|
||||
private_key: EcdsaSk<TestEnv>,
|
||||
application: &[u8; 32],
|
||||
) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
let aes_enc_key =
|
||||
crypto::aes256::EncryptionKey::new(&env.key_store().key_handle_encryption()?);
|
||||
let aes_key = AesKey::<TestEnv>::new(&env.key_store().key_handle_encryption()?);
|
||||
let mut plaintext = [0; 64];
|
||||
private_key.to_slice(array_mut_ref!(plaintext, 0, 32));
|
||||
plaintext[32..64].copy_from_slice(application);
|
||||
|
||||
let mut encrypted_id = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true)?;
|
||||
let mut encrypted_id =
|
||||
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true)?;
|
||||
let id_hmac = Hmac::<TestEnv>::mac(
|
||||
&env.key_store().key_handle_authentication()?,
|
||||
&encrypted_id[..],
|
||||
|
||||
@@ -12,23 +12,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::api::crypto::aes256::Aes256;
|
||||
use crate::api::crypto::ecdsa::{SecretKey as _, Signature};
|
||||
use crate::api::key_store::KeyStore;
|
||||
use crate::ctap::data_formats::{extract_array, extract_byte_string, CoseKey, SignatureAlgorithm};
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
use crate::env::{EcdsaSk, Env};
|
||||
use crate::env::{AesKey, EcdsaSk, Env};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryFrom;
|
||||
use crypto::cbc::{cbc_decrypt, cbc_encrypt};
|
||||
use rng256::Rng256;
|
||||
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(
|
||||
pub fn aes256_cbc_encrypt<E: Env>(
|
||||
rng: &mut dyn Rng256,
|
||||
aes_enc_key: &crypto::aes256::EncryptionKey,
|
||||
aes_key: &AesKey<E>,
|
||||
plaintext: &[u8],
|
||||
embeds_iv: bool,
|
||||
) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
@@ -46,13 +46,13 @@ pub fn aes256_cbc_encrypt(
|
||||
};
|
||||
let start = ciphertext.len();
|
||||
ciphertext.extend_from_slice(plaintext);
|
||||
cbc_encrypt(aes_enc_key, iv, &mut ciphertext[start..]);
|
||||
aes_key.encrypt_cbc(&iv, &mut ciphertext[start..]);
|
||||
Ok(ciphertext)
|
||||
}
|
||||
|
||||
/// Wraps the AES256-CBC decryption to match what we need in CTAP.
|
||||
pub fn aes256_cbc_decrypt(
|
||||
aes_enc_key: &crypto::aes256::EncryptionKey,
|
||||
pub fn aes256_cbc_decrypt<E: Env>(
|
||||
aes_key: &AesKey<E>,
|
||||
ciphertext: &[u8],
|
||||
embeds_iv: bool,
|
||||
) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
@@ -61,13 +61,12 @@ pub fn aes256_cbc_decrypt(
|
||||
}
|
||||
let (iv, ciphertext) = if embeds_iv {
|
||||
let (iv, ciphertext) = ciphertext.split_at(16);
|
||||
(*array_ref!(iv, 0, 16), ciphertext)
|
||||
(array_ref!(iv, 0, 16), ciphertext)
|
||||
} else {
|
||||
([0u8; 16], ciphertext)
|
||||
(&[0u8; 16], ciphertext)
|
||||
};
|
||||
let mut plaintext = ciphertext.to_vec();
|
||||
let aes_dec_key = crypto::aes256::DecryptionKey::new(aes_enc_key);
|
||||
cbc_decrypt(&aes_dec_key, iv, &mut plaintext);
|
||||
aes_key.decrypt_cbc(iv, &mut plaintext);
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
||||
@@ -226,58 +225,63 @@ mod test {
|
||||
#[test]
|
||||
fn test_encrypt_decrypt_with_iv() {
|
||||
let mut env = TestEnv::default();
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&[0xC2; 32]);
|
||||
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
|
||||
let plaintext = vec![0xAA; 64];
|
||||
let ciphertext = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt(&aes_enc_key, &ciphertext, true).unwrap();
|
||||
let ciphertext =
|
||||
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext, true).unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_decrypt_without_iv() {
|
||||
let mut env = TestEnv::default();
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&[0xC2; 32]);
|
||||
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
|
||||
let plaintext = vec![0xAA; 64];
|
||||
let ciphertext = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, false).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt(&aes_enc_key, &ciphertext, false).unwrap();
|
||||
let ciphertext =
|
||||
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, false).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext, false).unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_correct_iv_usage() {
|
||||
let mut env = TestEnv::default();
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&[0xC2; 32]);
|
||||
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
|
||||
let plaintext = vec![0xAA; 64];
|
||||
let mut ciphertext_no_iv =
|
||||
aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, false).unwrap();
|
||||
aes256_cbc_encrypt::<TestEnv>(env.rng(), &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(&aes_enc_key, &ciphertext_with_iv, true).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext_with_iv, true).unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iv_manipulation_property() {
|
||||
let mut env = TestEnv::default();
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&[0xC2; 32]);
|
||||
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
|
||||
let plaintext = vec![0xAA; 64];
|
||||
let mut ciphertext = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true).unwrap();
|
||||
let mut ciphertext =
|
||||
aes256_cbc_encrypt::<TestEnv>(env.rng(), &aes_key, &plaintext, true).unwrap();
|
||||
let mut expected_plaintext = plaintext;
|
||||
for i in 0..16 {
|
||||
ciphertext[i] ^= 0xBB;
|
||||
expected_plaintext[i] ^= 0xBB;
|
||||
}
|
||||
let decrypted = aes256_cbc_decrypt(&aes_enc_key, &ciphertext, true).unwrap();
|
||||
let decrypted = aes256_cbc_decrypt::<TestEnv>(&aes_key, &ciphertext, true).unwrap();
|
||||
assert_eq!(decrypted, expected_plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chaining() {
|
||||
let mut env = TestEnv::default();
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&[0xC2; 32]);
|
||||
let aes_key = AesKey::<TestEnv>::new(&[0xC2; 32]);
|
||||
let plaintext = vec![0xAA; 64];
|
||||
let ciphertext1 = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true).unwrap();
|
||||
let ciphertext2 = aes256_cbc_encrypt(env.rng(), &aes_enc_key, &plaintext, true).unwrap();
|
||||
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();
|
||||
assert_eq!(ciphertext1.len(), 80);
|
||||
assert_eq!(ciphertext2.len(), 80);
|
||||
// The ciphertext should mutate in all blocks with a different IV.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::api::crypto::aes256::Aes256;
|
||||
use crate::api::crypto::ecdh::{PublicKey as _, SecretKey as _, SharedSecret as _};
|
||||
use crate::api::crypto::hkdf256::Hkdf256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
@@ -22,9 +23,8 @@ use crate::ctap::data_formats::{CoseKey, PinUvAuthProtocol};
|
||||
use crate::ctap::status_code::Ctap2StatusCode;
|
||||
#[cfg(test)]
|
||||
use crate::env::test::TestEnv;
|
||||
use crate::env::{EcdhPk, EcdhSk, Env, Hkdf, Hmac, Sha};
|
||||
use crate::env::{AesKey, EcdhPk, EcdhSk, Env, Hkdf, Hmac, Sha};
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use rng256::Rng256;
|
||||
|
||||
/// Implements common functions between existing PIN protocols for handshakes.
|
||||
@@ -207,29 +207,26 @@ fn verify_v2<E: Env>(
|
||||
|
||||
pub struct SharedSecretV1<E: Env> {
|
||||
common_secret: [u8; 32],
|
||||
aes_enc_key: crypto::aes256::EncryptionKey,
|
||||
// TODO: remove after porting AES to env crypto
|
||||
phantom: PhantomData<E>,
|
||||
aes_key: AesKey<E>,
|
||||
}
|
||||
|
||||
impl<E: Env> SharedSecretV1<E> {
|
||||
/// Creates a new shared secret from the handshake result.
|
||||
fn new(handshake: [u8; 32]) -> Self {
|
||||
let common_secret = Sha::<E>::digest(&handshake);
|
||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&common_secret);
|
||||
let aes_key = AesKey::<E>::new(&common_secret);
|
||||
SharedSecretV1 {
|
||||
common_secret,
|
||||
aes_enc_key,
|
||||
phantom: PhantomData,
|
||||
aes_key,
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt(&self, rng: &mut dyn Rng256, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
aes256_cbc_encrypt(rng, &self.aes_enc_key, plaintext, false)
|
||||
aes256_cbc_encrypt::<E>(rng, &self.aes_key, plaintext, false)
|
||||
}
|
||||
|
||||
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
aes256_cbc_decrypt(&self.aes_enc_key, ciphertext, false)
|
||||
aes256_cbc_decrypt::<E>(&self.aes_key, ciphertext, false)
|
||||
}
|
||||
|
||||
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
||||
@@ -243,10 +240,8 @@ impl<E: Env> SharedSecretV1<E> {
|
||||
}
|
||||
|
||||
pub struct SharedSecretV2<E: Env> {
|
||||
aes_enc_key: crypto::aes256::EncryptionKey,
|
||||
aes_key: AesKey<E>,
|
||||
hmac_key: [u8; 32],
|
||||
// TODO: remove after porting AES to env crypto
|
||||
phantom: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: Env> SharedSecretV2<E> {
|
||||
@@ -254,18 +249,17 @@ impl<E: Env> SharedSecretV2<E> {
|
||||
fn new(handshake: [u8; 32]) -> Self {
|
||||
let aes_key = Hkdf::<E>::hkdf_empty_salt_256(&handshake, b"CTAP2 AES key");
|
||||
SharedSecretV2 {
|
||||
aes_enc_key: crypto::aes256::EncryptionKey::new(&aes_key),
|
||||
aes_key: AesKey::<E>::new(&aes_key),
|
||||
hmac_key: Hkdf::<E>::hkdf_empty_salt_256(&handshake, b"CTAP2 HMAC key"),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt(&self, rng: &mut dyn Rng256, plaintext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
aes256_cbc_encrypt(rng, &self.aes_enc_key, plaintext, true)
|
||||
aes256_cbc_encrypt::<E>(rng, &self.aes_key, plaintext, true)
|
||||
}
|
||||
|
||||
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
aes256_cbc_decrypt(&self.aes_enc_key, ciphertext, true)
|
||||
aes256_cbc_decrypt::<E>(&self.aes_key, ciphertext, true)
|
||||
}
|
||||
|
||||
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
||||
|
||||
1
libraries/opensk/src/env/mod.rs
vendored
1
libraries/opensk/src/env/mod.rs
vendored
@@ -29,6 +29,7 @@ use rng256::Rng256;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod test;
|
||||
|
||||
pub type AesKey<E> = <<E as Env>::Crypto as Crypto>::Aes256;
|
||||
pub type EcdhSk<E> = <<<E as Env>::Crypto as Crypto>::Ecdh as Ecdh>::SecretKey;
|
||||
pub type EcdhPk<E> = <<<E as Env>::Crypto as Crypto>::Ecdh as Ecdh>::PublicKey;
|
||||
pub type EcdsaSk<E> = <<<E as Env>::Crypto as Crypto>::Ecdsa as Ecdsa>::SecretKey;
|
||||
|
||||
Reference in New Issue
Block a user