Adds HKDF to the Crypto trait (#610)
This commit is contained in:
@@ -26,6 +26,7 @@ p256 = { version = "0.13.0", features = ["ecdh"], optional = true }
|
||||
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 }
|
||||
|
||||
[features]
|
||||
debug_ctap = []
|
||||
@@ -34,7 +35,7 @@ with_ctap1 = ["crypto/with_ctap1"]
|
||||
vendor_hid = []
|
||||
fuzz = ["arbitrary", "std"]
|
||||
ed25519 = ["ed25519-compact"]
|
||||
rust_crypto = ["p256", "rand_core", "sha2", "hmac"]
|
||||
rust_crypto = ["p256", "rand_core", "sha2", "hmac", "hkdf"]
|
||||
|
||||
[dev-dependencies]
|
||||
enum-iterator = "0.6.0"
|
||||
|
||||
26
libraries/opensk/src/api/crypto/hkdf256.rs
Normal file
26
libraries/opensk/src/api/crypto/hkdf256.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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::HASH_SIZE;
|
||||
|
||||
/// HKDF using SHA256.
|
||||
pub trait Hkdf256 {
|
||||
/// Computes the HKDF with empty salt and 256 bit (one block) output.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ikm` - Input keying material
|
||||
/// * `info` - Optional context and application specific information
|
||||
fn hkdf_empty_salt_256(ikm: &[u8], info: &[u8]) -> [u8; HASH_SIZE];
|
||||
}
|
||||
@@ -20,11 +20,13 @@ pub mod rust_crypto;
|
||||
pub mod software_crypto;
|
||||
#[cfg(feature = "rust_crypto")]
|
||||
pub use rust_crypto as software_crypto;
|
||||
pub mod hkdf256;
|
||||
pub mod hmac256;
|
||||
pub mod sha256;
|
||||
|
||||
use self::ecdh::Ecdh;
|
||||
use self::ecdsa::Ecdsa;
|
||||
use self::hkdf256::Hkdf256;
|
||||
use self::hmac256::Hmac256;
|
||||
use self::sha256::Sha256;
|
||||
|
||||
@@ -51,4 +53,5 @@ pub trait Crypto {
|
||||
type Ecdsa: Ecdsa;
|
||||
type Sha256: Sha256;
|
||||
type Hmac256: Hmac256;
|
||||
type Hkdf256: Hkdf256;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
//!
|
||||
//! If you want to use OpenSK outside of Tock v1, maybe this is useful for you though!
|
||||
|
||||
use crate::api::crypto::hkdf256::Hkdf256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
use crate::api::crypto::sha256::Sha256;
|
||||
use crate::api::crypto::{
|
||||
@@ -46,6 +47,7 @@ impl Crypto for SoftwareCrypto {
|
||||
type Ecdsa = SoftwareEcdsa;
|
||||
type Sha256 = SoftwareSha256;
|
||||
type Hmac256 = SoftwareHmac256;
|
||||
type Hkdf256 = SoftwareHkdf256;
|
||||
}
|
||||
|
||||
impl ecdh::Ecdh for SoftwareEcdh {
|
||||
@@ -248,6 +250,17 @@ impl Hmac256 for SoftwareHmac256 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SoftwareHkdf256;
|
||||
|
||||
impl Hkdf256 for SoftwareHkdf256 {
|
||||
fn hkdf_empty_salt_256(ikm: &[u8], info: &[u8]) -> [u8; HASH_SIZE] {
|
||||
let hk = hkdf::Hkdf::<sha2::Sha256>::new(Some(&[0; HASH_SIZE]), ikm);
|
||||
let mut okm = [0u8; HASH_SIZE];
|
||||
hk.expand(info, &mut okm).unwrap();
|
||||
okm
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -329,4 +342,14 @@ mod test {
|
||||
&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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::api::crypto::hkdf256::Hkdf256;
|
||||
use crate::api::crypto::hmac256::Hmac256;
|
||||
use crate::api::crypto::sha256::Sha256;
|
||||
use crate::api::crypto::{
|
||||
@@ -31,6 +32,7 @@ impl Crypto for SoftwareCrypto {
|
||||
type Ecdsa = SoftwareEcdsa;
|
||||
type Sha256 = SoftwareSha256;
|
||||
type Hmac256 = SoftwareHmac256;
|
||||
type Hkdf256 = SoftwareHkdf256;
|
||||
}
|
||||
|
||||
impl ecdh::Ecdh for SoftwareEcdh {
|
||||
@@ -201,6 +203,14 @@ impl Hmac256 for SoftwareHmac256 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SoftwareHkdf256;
|
||||
|
||||
impl Hkdf256 for SoftwareHkdf256 {
|
||||
fn hkdf_empty_salt_256(ikm: &[u8], info: &[u8]) -> [u8; HASH_SIZE] {
|
||||
crypto::hkdf::hkdf_empty_salt_256::<crypto::sha256::Sha256>(ikm, info)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -283,4 +293,14 @@ mod test {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
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::ctap::client_pin::PIN_TOKEN_LENGTH;
|
||||
@@ -21,10 +22,9 @@ 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, Hmac, Sha};
|
||||
use crate::env::{EcdhPk, EcdhSk, Env, Hkdf, Hmac, Sha};
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use crypto::hkdf::hkdf_empty_salt_256;
|
||||
use rng256::Rng256;
|
||||
|
||||
/// Implements common functions between existing PIN protocols for handshakes.
|
||||
@@ -252,10 +252,10 @@ pub struct SharedSecretV2<E: Env> {
|
||||
impl<E: Env> SharedSecretV2<E> {
|
||||
/// Creates a new shared secret from the handshake result.
|
||||
fn new(handshake: [u8; 32]) -> Self {
|
||||
let aes_key = hkdf_empty_salt_256::<crypto::sha256::Sha256>(&handshake, b"CTAP2 AES key");
|
||||
let aes_key = Hkdf::<E>::hkdf_empty_salt_256(&handshake, b"CTAP2 AES key");
|
||||
SharedSecretV2 {
|
||||
aes_enc_key: crypto::aes256::EncryptionKey::new(&aes_key),
|
||||
hmac_key: hkdf_empty_salt_256::<crypto::sha256::Sha256>(&handshake, b"CTAP2 HMAC key"),
|
||||
hmac_key: Hkdf::<E>::hkdf_empty_salt_256(&handshake, b"CTAP2 HMAC key"),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
1
libraries/opensk/src/env/mod.rs
vendored
1
libraries/opensk/src/env/mod.rs
vendored
@@ -35,6 +35,7 @@ pub type EcdsaSk<E> = <<<E as Env>::Crypto as Crypto>::Ecdsa as Ecdsa>::SecretKe
|
||||
pub type EcdsaPk<E> = <<<E as Env>::Crypto as Crypto>::Ecdsa as Ecdsa>::PublicKey;
|
||||
pub type Sha<E> = <<E as Env>::Crypto as Crypto>::Sha256;
|
||||
pub type Hmac<E> = <<E as Env>::Crypto as Crypto>::Hmac256;
|
||||
pub type Hkdf<E> = <<E as Env>::Crypto as Crypto>::Hkdf256;
|
||||
|
||||
/// Describes what CTAP needs to function.
|
||||
pub trait Env {
|
||||
|
||||
Reference in New Issue
Block a user