diff --git a/libraries/opensk/Cargo.toml b/libraries/opensk/Cargo.toml index 295bc0e..228041e 100644 --- a/libraries/opensk/Cargo.toml +++ b/libraries/opensk/Cargo.toml @@ -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" diff --git a/libraries/opensk/src/api/crypto/hkdf256.rs b/libraries/opensk/src/api/crypto/hkdf256.rs new file mode 100644 index 0000000..8461fe1 --- /dev/null +++ b/libraries/opensk/src/api/crypto/hkdf256.rs @@ -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]; +} diff --git a/libraries/opensk/src/api/crypto/mod.rs b/libraries/opensk/src/api/crypto/mod.rs index 7479c8d..0936e55 100644 --- a/libraries/opensk/src/api/crypto/mod.rs +++ b/libraries/opensk/src/api/crypto/mod.rs @@ -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; } diff --git a/libraries/opensk/src/api/crypto/rust_crypto.rs b/libraries/opensk/src/api/crypto/rust_crypto.rs index d43785e..752657b 100644 --- a/libraries/opensk/src/api/crypto/rust_crypto.rs +++ b/libraries/opensk/src/api/crypto/rust_crypto.rs @@ -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::::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); + } } diff --git a/libraries/opensk/src/api/crypto/software_crypto.rs b/libraries/opensk/src/api/crypto/software_crypto.rs index 400e7b5..8efa194 100644 --- a/libraries/opensk/src/api/crypto/software_crypto.rs +++ b/libraries/opensk/src/api/crypto/software_crypto.rs @@ -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::(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); + } } diff --git a/libraries/opensk/src/ctap/pin_protocol.rs b/libraries/opensk/src/ctap/pin_protocol.rs index 43d3d6b..19aea01 100644 --- a/libraries/opensk/src/ctap/pin_protocol.rs +++ b/libraries/opensk/src/ctap/pin_protocol.rs @@ -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 { impl SharedSecretV2 { /// Creates a new shared secret from the handshake result. fn new(handshake: [u8; 32]) -> Self { - let aes_key = hkdf_empty_salt_256::(&handshake, b"CTAP2 AES key"); + let aes_key = Hkdf::::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::(&handshake, b"CTAP2 HMAC key"), + hmac_key: Hkdf::::hkdf_empty_salt_256(&handshake, b"CTAP2 HMAC key"), phantom: PhantomData, } } diff --git a/libraries/opensk/src/env/mod.rs b/libraries/opensk/src/env/mod.rs index 9b0c5bc..9c86f23 100644 --- a/libraries/opensk/src/env/mod.rs +++ b/libraries/opensk/src/env/mod.rs @@ -35,6 +35,7 @@ pub type EcdsaSk = <<::Crypto as Crypto>::Ecdsa as Ecdsa>::SecretKe pub type EcdsaPk = <<::Crypto as Crypto>::Ecdsa as Ecdsa>::PublicKey; pub type Sha = <::Crypto as Crypto>::Sha256; pub type Hmac = <::Crypto as Crypto>::Hmac256; +pub type Hkdf = <::Crypto as Crypto>::Hkdf256; /// Describes what CTAP needs to function. pub trait Env {