Adds HKDF to the Crypto trait (#610)

This commit is contained in:
kaczmarczyck
2023-04-04 17:48:56 +02:00
committed by GitHub
parent 22192a37d2
commit d0cdbec5ce
7 changed files with 79 additions and 5 deletions

View File

@@ -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"

View 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];
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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,
}
}

View File

@@ -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 {