diff --git a/Cargo.toml b/Cargo.toml index 37212ef4..0e16567f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "crypto/edhoc-crypto-hacspec", "crypto/edhoc-crypto-psa", "crypto/edhoc-crypto-cryptocell310-sys", + "crypto/edhoc-crypto-trait", "examples/coap", "examples/edhoc-rs-no_std", "examples/edhoc-rs-cc2538", diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 7a27aa8c..2856c2fa 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -9,6 +9,8 @@ description = "EDHOC crypto library dispatch crate" [dependencies] edhoc-consts = { path = "../consts", default-features = false } +edhoc-crypto-trait.path = "./edhoc-crypto-trait" + # hacspec edhoc-crypto-hacspec = { path = "./edhoc-crypto-hacspec", optional = true } diff --git a/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml b/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml index 03739a11..239166fe 100644 --- a/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml +++ b/crypto/edhoc-crypto-cryptocell310-sys/Cargo.toml @@ -9,6 +9,7 @@ links = "nrf_cc310_0.9.13" [dependencies] edhoc-consts = { path = "../../consts" } +edhoc-crypto-trait.path = "../edhoc-crypto-trait" [build-dependencies] bindgen = "0.63.0" diff --git a/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs b/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs index be73d460..460ea8fc 100644 --- a/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs +++ b/crypto/edhoc-crypto-cryptocell310-sys/src/lib.rs @@ -8,6 +8,8 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs")); use core::ffi::c_void; use edhoc_consts::*; +use edhoc_crypto_trait::Crypto as CryptoTrait; + fn convert_array(input: &[u32]) -> [u8; SHA256_DIGEST_LEN] { assert!(input.len() == SHA256_DIGEST_LEN / 4); @@ -18,181 +20,271 @@ fn convert_array(input: &[u32]) -> [u8; SHA256_DIGEST_LEN] { output } -pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; +pub struct Crypto; - unsafe { - CRYS_HASH( - CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, - message.clone().as_mut_ptr(), - message_len, - buffer.as_mut_ptr(), - ); - } +impl CryptoTrait for Crypto { + fn sha256_digest(&mut self, message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { + let mut buffer: [u32; 64 / 4] = [0x00; 64 / 4]; - convert_array(&buffer[0..SHA256_DIGEST_LEN / 4]) -} + unsafe { + CRYS_HASH( + CRYS_HASH_OperationMode_t_CRYS_HASH_SHA256_mode, + message.clone().as_mut_ptr(), + message_len, + buffer.as_mut_ptr(), + ); + } -pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, -) -> BytesMaxBuffer { - let mut buffer = [0x00u8; MAX_BUFFER_LEN]; - unsafe { - CRYS_HKDF_KeyDerivFunc( - CRYS_HKDF_HASH_OpMode_t_CRYS_HKDF_HASH_SHA256_mode, - core::ptr::null_mut(), - 0 as usize, - prk.clone().as_mut_ptr(), - prk.len() as u32, - info.clone().as_mut_ptr(), - info_len as u32, - buffer.as_mut_ptr(), - length as u32, - SaSiBool_SASI_TRUE, - ); + convert_array(&buffer[0..SHA256_DIGEST_LEN / 4]) } - buffer -} + fn hkdf_expand( + &mut self, + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, + ) -> BytesMaxBuffer { + let mut buffer = [0x00u8; MAX_BUFFER_LEN]; + unsafe { + CRYS_HKDF_KeyDerivFunc( + CRYS_HKDF_HASH_OpMode_t_CRYS_HKDF_HASH_SHA256_mode, + core::ptr::null_mut(), + 0 as usize, + prk.clone().as_mut_ptr(), + prk.len() as u32, + info.clone().as_mut_ptr(), + info_len as u32, + buffer.as_mut_ptr(), + length as u32, + SaSiBool_SASI_TRUE, + ); + } -pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 + buffer + } - // TODO generalize if salt is not provided - let output = hmac_sha256(&mut ikm.clone()[..], *salt); + fn hkdf_extract(&mut self, salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { + // Implementation of HKDF-Extract as per RFC 5869 - output -} + // TODO generalize if salt is not provided + let output = hmac_sha256(&mut ikm.clone()[..], *salt); -pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, -) -> BufferCiphertext3 { - let mut output: BufferCiphertext3 = BufferCiphertext3::new(); - let mut tag: CRYS_AESCCM_Mac_Res_t = Default::default(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); - - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); - - let err = unsafe { - CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_ENCRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.clone().as_mut_ptr(), - iv.len() as u8, - ad.clone().as_mut_ptr(), - ad.len() as u32, - plaintext.content.clone().as_mut_ptr(), - plaintext.len as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - tag.as_mut_ptr(), - 0 as u32, // CCM - ) - }; - - output.content[plaintext.len..plaintext.len + AES_CCM_TAG_LEN] - .copy_from_slice(&tag[..AES_CCM_TAG_LEN]); - output.len = plaintext.len + AES_CCM_TAG_LEN; + output + } - output -} + fn aes_ccm_encrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, + ) -> BufferCiphertext3 { + let mut output: BufferCiphertext3 = BufferCiphertext3::new(); + let mut tag: CRYS_AESCCM_Mac_Res_t = Default::default(); + let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); + + aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); + + let err = unsafe { + CC_AESCCM( + SaSiAesEncryptMode_t_SASI_AES_ENCRYPT, + aesccm_key.as_mut_ptr(), + CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, + iv.clone().as_mut_ptr(), + iv.len() as u8, + ad.clone().as_mut_ptr(), + ad.len() as u32, + plaintext.content.clone().as_mut_ptr(), + plaintext.len as u32, + output.content.as_mut_ptr(), + AES_CCM_TAG_LEN as u8, // authentication tag length + tag.as_mut_ptr(), + 0 as u32, // CCM + ) + }; + + output.content[plaintext.len..plaintext.len + AES_CCM_TAG_LEN] + .copy_from_slice(&tag[..AES_CCM_TAG_LEN]); + output.len = plaintext.len + AES_CCM_TAG_LEN; + + output + } + + fn aes_ccm_decrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, + ) -> Result { + let mut output: BufferPlaintext3 = BufferPlaintext3::new(); + let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); + + aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); + + let mut err = EDHOCError::MacVerificationFailed; + + unsafe { + match CC_AESCCM( + SaSiAesEncryptMode_t_SASI_AES_DECRYPT, + aesccm_key.as_mut_ptr(), + CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, + iv.clone().as_mut_ptr(), + iv.len() as u8, + ad.clone().as_mut_ptr(), + ad.len() as u32, + ciphertext.content.clone().as_mut_ptr(), + (ciphertext.len - AES_CCM_TAG_LEN) as u32, + output.content.as_mut_ptr(), + AES_CCM_TAG_LEN as u8, // authentication tag length + ciphertext.content.clone()[ciphertext.len - AES_CCM_TAG_LEN..].as_mut_ptr(), + 0 as u32, // CCM + ) { + CRYS_OK => { + output.len = ciphertext.len - AES_CCM_TAG_LEN; + Ok(output) + } + _ => Err(EDHOCError::MacVerificationFailed), + } + } + } -pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, -) -> Result { - let mut output: BufferPlaintext3 = BufferPlaintext3::new(); - let mut aesccm_key: CRYS_AESCCM_Key_t = Default::default(); + fn p256_ecdh( + &mut self, + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, + ) -> BytesP256ElemLen { + let mut output = [0x0u8; P256_ELEM_LEN]; + let mut output_len: u32 = output.len() as u32; + + let mut tmp: CRYS_ECDH_TempData_t = Default::default(); + + let mut public_key_compressed = [0x0u8; P256_ELEM_LEN + 1]; + public_key_compressed[0] = 0x02; + public_key_compressed[1..].copy_from_slice(&public_key[..]); + + let mut public_key_cc310: CRYS_ECPKI_UserPublKey_t = Default::default(); + + let mut domain = + unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; + + unsafe { + _DX_ECPKI_BuildPublKey( + domain, + public_key_compressed.as_mut_ptr(), + (P256_ELEM_LEN + 1) as u32, + EC_PublKeyCheckMode_t_CheckPointersAndSizesOnly, + &mut public_key_cc310, + core::ptr::null_mut(), + ); + } - aesccm_key[0..AES_CCM_KEY_LEN].copy_from_slice(&key[..]); + let mut private_key_cc310: CRYS_ECPKI_UserPrivKey_t = Default::default(); - let mut err = EDHOCError::MacVerificationFailed; + unsafe { + CRYS_ECPKI_BuildPrivKey( + domain, + private_key.clone().as_mut_ptr(), + P256_ELEM_LEN as u32, + &mut private_key_cc310, + ); + } - unsafe { - match CC_AESCCM( - SaSiAesEncryptMode_t_SASI_AES_DECRYPT, - aesccm_key.as_mut_ptr(), - CRYS_AESCCM_KeySize_t_CRYS_AES_Key128BitSize, - iv.clone().as_mut_ptr(), - iv.len() as u8, - ad.clone().as_mut_ptr(), - ad.len() as u32, - ciphertext.content.clone().as_mut_ptr(), - (ciphertext.len - AES_CCM_TAG_LEN) as u32, - output.content.as_mut_ptr(), - AES_CCM_TAG_LEN as u8, // authentication tag length - ciphertext.content.clone()[ciphertext.len - AES_CCM_TAG_LEN..].as_mut_ptr(), - 0 as u32, // CCM - ) { - CRYS_OK => { - output.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(output) - } - _ => Err(EDHOCError::MacVerificationFailed), + unsafe { + CRYS_ECDH_SVDP_DH( + &mut public_key_cc310, + &mut private_key_cc310, + output.as_mut_ptr(), + &mut output_len, + &mut tmp, + ); } + + output } -} -pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, -) -> BytesP256ElemLen { - let mut output = [0x0u8; P256_ELEM_LEN]; - let mut output_len: u32 = output.len() as u32; + fn get_random_byte(&mut self) -> u8 { + let mut rnd_context = CRYS_RND_State_t::default(); + let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); + unsafe { + SaSi_LibInit(); + CRYS_RndInit( + &mut rnd_context as *mut _ as *mut c_void, + &mut rnd_work_buffer as *mut _, + ); + } + let mut buffer = [0u8; 1]; + unsafe { + CRYS_RND_GenerateVector( + &mut rnd_context as *mut _ as *mut c_void, + 1, + buffer.as_mut_ptr(), + ); + } + buffer[0] + } - let mut tmp: CRYS_ECDH_TempData_t = Default::default(); + fn p256_generate_key_pair(&mut self) -> (BytesP256ElemLen, BytesP256ElemLen) { + let mut rnd_context = CRYS_RND_State_t::default(); + let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); + unsafe { + SaSi_LibInit(); + CRYS_RndInit( + &mut rnd_context as *mut _ as *mut c_void, + &mut rnd_work_buffer as *mut _, + ); + } + let rnd_generate_vect_func: SaSiRndGenerateVectWorkFunc_t = Some(CRYS_RND_GenerateVector); + let mut curve_256 = + unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; + let mut crys_private_key: *mut CRYS_ECPKI_UserPrivKey_t = + &mut CRYS_ECPKI_UserPrivKey_t::default(); + let mut crys_public_key: *mut CRYS_ECPKI_UserPublKey_t = + &mut CRYS_ECPKI_UserPublKey_t::default(); + let mut temp_data: *mut CRYS_ECPKI_KG_TempData_t = &mut CRYS_ECPKI_KG_TempData_t::default(); + let mut temp_fips_buffer: *mut CRYS_ECPKI_KG_FipsContext_t = + &mut CRYS_ECPKI_KG_FipsContext_t::default(); + + unsafe { + CRYS_ECPKI_GenKeyPair( + &mut rnd_context as *mut _ as *mut c_void, + rnd_generate_vect_func, + curve_256, + crys_private_key, + crys_public_key, + temp_data, + temp_fips_buffer, + ); + } - let mut public_key_compressed = [0x0u8; P256_ELEM_LEN + 1]; - public_key_compressed[0] = 0x02; - public_key_compressed[1..].copy_from_slice(&public_key[..]); + let mut private_key: [u8; P256_ELEM_LEN] = [0x0; P256_ELEM_LEN]; + let mut key_size: u32 = P256_ELEM_LEN.try_into().unwrap(); - let mut public_key_cc310: CRYS_ECPKI_UserPublKey_t = Default::default(); + unsafe { + CRYS_ECPKI_ExportPrivKey(crys_private_key, private_key.as_mut_ptr(), &mut key_size); + } - let mut domain = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; + // let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - unsafe { - _DX_ECPKI_BuildPublKey( - domain, - public_key_compressed.as_mut_ptr(), - (P256_ELEM_LEN + 1) as u32, - EC_PublKeyCheckMode_t_CheckPointersAndSizesOnly, - &mut public_key_cc310, - core::ptr::null_mut(), - ); - } + let mut public_key: [u8; P256_ELEM_LEN + 1] = [0x0; P256_ELEM_LEN + 1]; + let mut key_size: u32 = (P256_ELEM_LEN as u32) + 1; + let compressed_flag: CRYS_ECPKI_PointCompression_t = + CRYS_ECPKI_PointCompression_t_CRYS_EC_PointCompressed; - let mut private_key_cc310: CRYS_ECPKI_UserPrivKey_t = Default::default(); + unsafe { + CRYS_ECPKI_ExportPublKey( + crys_public_key, + compressed_flag, + public_key.as_mut_ptr(), + &mut key_size, + ); + } - unsafe { - CRYS_ECPKI_BuildPrivKey( - domain, - private_key.clone().as_mut_ptr(), - P256_ELEM_LEN as u32, - &mut private_key_cc310, - ); - } + let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // discard sign byte - unsafe { - CRYS_ECDH_SVDP_DH( - &mut public_key_cc310, - &mut private_key_cc310, - output.as_mut_ptr(), - &mut output_len, - &mut tmp, - ); + (private_key, public_key) } - - output } fn hmac_sha256(message: &mut [u8], mut key: [u8; SHA256_DIGEST_LEN]) -> BytesHashLen { @@ -211,85 +303,3 @@ fn hmac_sha256(message: &mut [u8], mut key: [u8; SHA256_DIGEST_LEN]) -> BytesHas convert_array(&buffer[..SHA256_DIGEST_LEN / 4]) } - -pub fn get_random_byte() -> u8 { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let mut buffer = [0u8; 1]; - unsafe { - CRYS_RND_GenerateVector( - &mut rnd_context as *mut _ as *mut c_void, - 1, - buffer.as_mut_ptr(), - ); - } - buffer[0] -} - -pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let mut rnd_context = CRYS_RND_State_t::default(); - let mut rnd_work_buffer = CRYS_RND_WorkBuff_t::default(); - unsafe { - SaSi_LibInit(); - CRYS_RndInit( - &mut rnd_context as *mut _ as *mut c_void, - &mut rnd_work_buffer as *mut _, - ); - } - let rnd_generate_vect_func: SaSiRndGenerateVectWorkFunc_t = Some(CRYS_RND_GenerateVector); - let mut curve_256 = - unsafe { CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t_CRYS_ECPKI_DomainID_secp256r1) }; - let mut crys_private_key: *mut CRYS_ECPKI_UserPrivKey_t = - &mut CRYS_ECPKI_UserPrivKey_t::default(); - let mut crys_public_key: *mut CRYS_ECPKI_UserPublKey_t = - &mut CRYS_ECPKI_UserPublKey_t::default(); - let mut temp_data: *mut CRYS_ECPKI_KG_TempData_t = &mut CRYS_ECPKI_KG_TempData_t::default(); - let mut temp_fips_buffer: *mut CRYS_ECPKI_KG_FipsContext_t = - &mut CRYS_ECPKI_KG_FipsContext_t::default(); - - unsafe { - CRYS_ECPKI_GenKeyPair( - &mut rnd_context as *mut _ as *mut c_void, - rnd_generate_vect_func, - curve_256, - crys_private_key, - crys_public_key, - temp_data, - temp_fips_buffer, - ); - } - - let mut private_key: [u8; P256_ELEM_LEN] = [0x0; P256_ELEM_LEN]; - let mut key_size: u32 = P256_ELEM_LEN.try_into().unwrap(); - - unsafe { - CRYS_ECPKI_ExportPrivKey(crys_private_key, private_key.as_mut_ptr(), &mut key_size); - } - - // let private_key = BytesP256ElemLen::from_public_slice(&private_key[..]); - - let mut public_key: [u8; P256_ELEM_LEN + 1] = [0x0; P256_ELEM_LEN + 1]; - let mut key_size: u32 = (P256_ELEM_LEN as u32) + 1; - let compressed_flag: CRYS_ECPKI_PointCompression_t = - CRYS_ECPKI_PointCompression_t_CRYS_EC_PointCompressed; - - unsafe { - CRYS_ECPKI_ExportPublKey( - crys_public_key, - compressed_flag, - public_key.as_mut_ptr(), - &mut key_size, - ); - } - - let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // discard sign byte - - (private_key, public_key) -} diff --git a/crypto/edhoc-crypto-hacspec/Cargo.toml b/crypto/edhoc-crypto-hacspec/Cargo.toml index df741064..1d4eda20 100644 --- a/crypto/edhoc-crypto-hacspec/Cargo.toml +++ b/crypto/edhoc-crypto-hacspec/Cargo.toml @@ -8,6 +8,7 @@ description = "EDHOC crypto library hacspec backend" [dependencies] edhoc-consts = { path = "../../consts", default-features = false } +edhoc-crypto-trait.path = "../edhoc-crypto-trait" hacspec-lib = { version = "0.1.0-beta.1", default-features = false } hacspec-p256 = { version = "0.1.0" } hacspec-hkdf = { version = "0.1.0" } diff --git a/crypto/edhoc-crypto-hacspec/src/lib.rs b/crypto/edhoc-crypto-hacspec/src/lib.rs index 350fe741..a7a46ea9 100644 --- a/crypto/edhoc-crypto-hacspec/src/lib.rs +++ b/crypto/edhoc-crypto-hacspec/src/lib.rs @@ -9,6 +9,8 @@ use hacspec_p256::*; use hacspec_sha256::*; use rand::Rng; +use edhoc_crypto_trait::Crypto as CryptoTrait; + // Types and functions to aid in translation between the hacspec and non-hacspec world // TODO: the `array!` construct is not needed anymore. @@ -70,143 +72,151 @@ type BufferPlaintext3Hacspec = EdhocMessageBufferHacspec; // Public functions -pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let message: BytesMaxBufferHacspec = BytesMaxBufferHacspec::from_public_slice(message); +pub struct Crypto; - let output = - BytesHashLenHacspec::from_seq(&hash(&ByteSeq::from_slice(&message, 0, message_len))); +impl CryptoTrait for Crypto { + fn sha256_digest(&mut self, message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { + let message: BytesMaxBufferHacspec = BytesMaxBufferHacspec::from_public_slice(message); - output.to_public_array() -} + let output = + BytesHashLenHacspec::from_seq(&hash(&ByteSeq::from_slice(&message, 0, message_len))); + + output.to_public_array() + } + + fn hkdf_expand( + &mut self, + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, + ) -> BytesMaxBuffer { + let mut output = BytesMaxBufferHacspec::new(); + output = output.update( + 0, + &expand( + &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(prk), 0, prk.len()), + &ByteSeq::from_slice( + &BytesMaxInfoBufferHacspec::from_public_slice(info), + 0, + info_len, + ), + length, + ) + .unwrap(), + ); + output.to_public_array() + } -pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, -) -> BytesMaxBuffer { - let mut output = BytesMaxBufferHacspec::new(); - output = output.update( - 0, - &expand( - &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(prk), 0, prk.len()), + fn hkdf_extract(&mut self, salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { + let output = BytesHashLenHacspec::from_seq(&extract( + &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(salt), 0, salt.len()), &ByteSeq::from_slice( - &BytesMaxInfoBufferHacspec::from_public_slice(info), + &BytesP256ElemLenHacspec::from_public_slice(ikm), 0, - info_len, + ikm.len(), ), - length, - ) - .unwrap(), - ); - output.to_public_array() -} + )); + output.to_public_array() + } -pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - let output = BytesHashLenHacspec::from_seq(&extract( - &ByteSeq::from_slice(&BytesHashLenHacspec::from_public_slice(salt), 0, salt.len()), - &ByteSeq::from_slice( - &BytesP256ElemLenHacspec::from_public_slice(ikm), - 0, - ikm.len(), - ), - )); - output.to_public_array() -} + fn aes_ccm_encrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, + ) -> BufferCiphertext3 { + let plaintext = BufferPlaintext3Hacspec::from_public_buffer(plaintext); + + let output = BufferCiphertext3Hacspec::from_seq(&encrypt_ccm( + ByteSeq::from_slice( + &BytesEncStructureLenHacspec::from_public_slice(ad), + 0, + ad.len(), + ), + ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), + ByteSeq::from_slice(&plaintext.content, 0, plaintext.len), + Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), + AES_CCM_TAG_LEN, + )); -pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, -) -> BufferCiphertext3 { - let plaintext = BufferPlaintext3Hacspec::from_public_buffer(plaintext); - - let output = BufferCiphertext3Hacspec::from_seq(&encrypt_ccm( - ByteSeq::from_slice( - &BytesEncStructureLenHacspec::from_public_slice(ad), - 0, - ad.len(), - ), - ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), - ByteSeq::from_slice(&plaintext.content, 0, plaintext.len), - Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), - AES_CCM_TAG_LEN, - )); - - output.to_public_buffer() -} + output.to_public_buffer() + } -pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, -) -> Result { - let ciphertext = BufferCiphertext3Hacspec::from_public_buffer(ciphertext); - - match decrypt_ccm( - ByteSeq::from_slice( - &BytesEncStructureLenHacspec::from_public_slice(ad), - 0, - ad.len(), - ), - ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), - Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), - ByteSeq::from_slice(&ciphertext.content, 0, ciphertext.len), - ciphertext.len, - AES_CCM_TAG_LEN, - ) { - Ok(p) => Ok(BufferPlaintext3Hacspec::from_seq(&p).to_public_buffer()), - Err(_) => Err(EDHOCError::MacVerificationFailed), + fn aes_ccm_decrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, + ) -> Result { + let ciphertext = BufferCiphertext3Hacspec::from_public_buffer(ciphertext); + + match decrypt_ccm( + ByteSeq::from_slice( + &BytesEncStructureLenHacspec::from_public_slice(ad), + 0, + ad.len(), + ), + ByteSeq::from_slice(&BytesCcmIvLenHacspec::from_public_slice(iv), 0, iv.len()), + Key128::from_slice(&BytesCcmKeyLenHacspec::from_public_slice(key), 0, key.len()), + ByteSeq::from_slice(&ciphertext.content, 0, ciphertext.len), + ciphertext.len, + AES_CCM_TAG_LEN, + ) { + Ok(p) => Ok(BufferPlaintext3Hacspec::from_seq(&p).to_public_buffer()), + Err(_) => Err(EDHOCError::MacVerificationFailed), + } } -} -pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, -) -> BytesP256ElemLen { - let private_key = BytesP256ElemLenHacspec::from_public_slice(private_key); - let public_key = BytesP256ElemLenHacspec::from_public_slice(public_key); + fn p256_ecdh( + &mut self, + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, + ) -> BytesP256ElemLen { + let private_key = BytesP256ElemLenHacspec::from_public_slice(private_key); + let public_key = BytesP256ElemLenHacspec::from_public_slice(public_key); - let scalar = P256Scalar::from_byte_seq_be(&private_key); - let point = ( - P256FieldElement::from_byte_seq_be(&public_key), - p256_calculate_w(P256FieldElement::from_byte_seq_be(&public_key)), - ); + let scalar = P256Scalar::from_byte_seq_be(&private_key); + let point = ( + P256FieldElement::from_byte_seq_be(&public_key), + p256_calculate_w(P256FieldElement::from_byte_seq_be(&public_key)), + ); - // we only care about the x coordinate - let (x, _y) = p256_point_mul(scalar, point).unwrap(); + // we only care about the x coordinate + let (x, _y) = p256_point_mul(scalar, point).unwrap(); - let secret = BytesP256ElemLenHacspec::from_seq(&x.to_byte_seq_be()); + let secret = BytesP256ElemLenHacspec::from_seq(&x.to_byte_seq_be()); - secret.to_public_array() -} + secret.to_public_array() + } -#[cfg(not(feature = "hacspec-pure"))] -pub fn get_random_byte() -> u8 { - rand::thread_rng().gen::() -} + #[cfg(not(feature = "hacspec-pure"))] + fn get_random_byte(&mut self) -> u8 { + rand::thread_rng().gen::() + } -#[cfg(not(feature = "hacspec-pure"))] -pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - // generate a private key - let mut private_key = BytesP256ElemLenHacspec::new(); - loop { - for i in 0..private_key.len() { - private_key[i] = U8(rand::thread_rng().gen::()); + #[cfg(not(feature = "hacspec-pure"))] + fn p256_generate_key_pair(&mut self) -> (BytesP256ElemLen, BytesP256ElemLen) { + // generate a private key + let mut private_key = BytesP256ElemLenHacspec::new(); + loop { + for i in 0..private_key.len() { + private_key[i] = U8(rand::thread_rng().gen::()); + } + if p256_validate_private_key(&ByteSeq::from_slice(&private_key, 0, private_key.len())) { + break; + } } - if p256_validate_private_key(&ByteSeq::from_slice(&private_key, 0, private_key.len())) { - break; - } - } - // obtain the corresponding public key - let scalar = P256Scalar::from_byte_seq_be(&private_key); - let public_key_point = p256_point_mul_base(scalar).unwrap(); - let public_key = BytesP256ElemLenHacspec::from_seq(&public_key_point.0.to_byte_seq_be()); + // obtain the corresponding public key + let scalar = P256Scalar::from_byte_seq_be(&private_key); + let public_key_point = p256_point_mul_base(scalar).unwrap(); + let public_key = BytesP256ElemLenHacspec::from_seq(&public_key_point.0.to_byte_seq_be()); - (private_key.to_public_array(), public_key.to_public_array()) + (private_key.to_public_array(), public_key.to_public_array()) + } } #[cfg(test)] @@ -215,14 +225,14 @@ mod tests { #[test] fn test_p256_keys() { - let (x, g_x) = p256_generate_key_pair(); + let (x, g_x) = Crypto.p256_generate_key_pair(); assert_eq!(x.len(), 32); assert_eq!(g_x.len(), 32); - let (y, g_y) = p256_generate_key_pair(); + let (y, g_y) = Crypto.p256_generate_key_pair(); - let g_xy = p256_ecdh(&x, &g_y); - let g_yx = p256_ecdh(&y, &g_x); + let g_xy = Crypto.p256_ecdh(&x, &g_y); + let g_yx = Crypto.p256_ecdh(&y, &g_x); assert_eq!(g_xy, g_yx); } diff --git a/crypto/edhoc-crypto-psa/Cargo.toml b/crypto/edhoc-crypto-psa/Cargo.toml index d3df8a5e..3f66bd25 100644 --- a/crypto/edhoc-crypto-psa/Cargo.toml +++ b/crypto/edhoc-crypto-psa/Cargo.toml @@ -8,6 +8,7 @@ description = "EDHOC crypto library PSA backend" [dependencies] edhoc-consts = { path = "../../consts" } +edhoc-crypto-trait.path = "../edhoc-crypto-trait" psa-crypto = { version = "0.9.2" } [features] diff --git a/crypto/edhoc-crypto-psa/src/lib.rs b/crypto/edhoc-crypto-psa/src/lib.rs index 938ba1dc..a8ed7cb6 100644 --- a/crypto/edhoc-crypto-psa/src/lib.rs +++ b/crypto/edhoc-crypto-psa/src/lib.rs @@ -7,6 +7,8 @@ use psa_crypto::types::algorithm::Hash; use psa_crypto::types::algorithm::{Aead, AeadWithDefaultLengthTag, KeyAgreement, RawKeyAgreement}; use psa_crypto::types::key::{Attributes, EccFamily, Lifetime, Policy, Type, UsageFlags}; +use edhoc_crypto_trait::Crypto as CryptoTrait; + #[no_mangle] pub extern "C" fn mbedtls_hardware_poll( data: *mut ::core::ffi::c_void, @@ -20,180 +22,229 @@ pub extern "C" fn mbedtls_hardware_poll( 0i32 } -pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { - let hash_alg = Hash::Sha256; - let mut hash: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN]; - psa_crypto::init().unwrap(); - hash_compute(hash_alg, &message[..message_len], &mut hash).unwrap(); +pub struct Crypto; - hash -} +impl CryptoTrait for Crypto { + fn sha256_digest(&mut self, message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen { + let hash_alg = Hash::Sha256; + let mut hash: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN]; + psa_crypto::init().unwrap(); + hash_compute(hash_alg, &message[..message_len], &mut hash).unwrap(); -pub fn hkdf_expand( - prk: &BytesHashLen, - info: &BytesMaxInfoBuffer, - info_len: usize, - length: usize, -) -> BytesMaxBuffer { - // Implementation of HKDF-Expand as per RFC5869 + hash + } - let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; + // FIXME: Together with hkdf_extract, and the hmac_sha256 helper, this could be a provided + // function. + fn hkdf_expand( + &mut self, + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, + ) -> BytesMaxBuffer { + // Implementation of HKDF-Expand as per RFC5869 + + let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN]; + + let mut n = 0; + + // N = ceil(L/HashLen) + if length % SHA256_DIGEST_LEN == 0 { + n = length / SHA256_DIGEST_LEN; + } else { + n = length / SHA256_DIGEST_LEN + 1; + } - let mut n = 0; + let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] = + [0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1]; + message[..info_len].copy_from_slice(&info[..info_len]); + message[info_len] = 0x01; + let mut t_i = hmac_sha256(&message[..info_len + 1], prk); + output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); + + for i in 2..n { + message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); + message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len] + .copy_from_slice(&info[..info_len]); + message[SHA256_DIGEST_LEN + info_len] = i as u8; + t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk); + output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); + } - // N = ceil(L/HashLen) - if length % SHA256_DIGEST_LEN == 0 { - n = length / SHA256_DIGEST_LEN; - } else { - n = length / SHA256_DIGEST_LEN + 1; - } + output[length..].fill(0x00); - let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] = - [0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1]; - message[..info_len].copy_from_slice(&info[..info_len]); - message[info_len] = 0x01; - let mut t_i = hmac_sha256(&message[..info_len + 1], prk); - output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - - for i in 2..n { - message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i); - message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len].copy_from_slice(&info[..info_len]); - message[SHA256_DIGEST_LEN + info_len] = i as u8; - t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk); - output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i); + output } - output[length..].fill(0x00); + fn hkdf_extract(&mut self, salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { + // Implementation of HKDF-Extract as per RFC 5869 - output -} + // TODO generalize if salt is not provided + let output = hmac_sha256(ikm, salt); -pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen { - // Implementation of HKDF-Extract as per RFC 5869 + output + } - // TODO generalize if salt is not provided - let output = hmac_sha256(ikm, salt); + fn aes_ccm_encrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, + ) -> BufferCiphertext3 { + psa_crypto::init().unwrap(); + + let alg = Aead::AeadWithShortenedTag { + aead_alg: AeadWithDefaultLengthTag::Ccm, + tag_length: 8, + }; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_encrypt(); + + let attributes = Attributes { + key_type: Type::Aes, + bits: 128, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: alg.into(), + }, + }; + let my_key = key_management::import(attributes, None, &key[..]).unwrap(); + let mut output_buffer: BufferCiphertext3 = BufferCiphertext3::new(); + + aead::encrypt( + my_key, + alg, + iv, + ad, + &plaintext.content[..plaintext.len], + &mut output_buffer.content, + ) + .unwrap(); + + output_buffer.len = plaintext.len + AES_CCM_TAG_LEN; + output_buffer + } - output -} + fn aes_ccm_decrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, + ) -> Result { + psa_crypto::init().unwrap(); + + let alg = Aead::AeadWithShortenedTag { + aead_alg: AeadWithDefaultLengthTag::Ccm, + tag_length: 8, + }; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_decrypt(); + + let attributes = Attributes { + key_type: Type::Aes, + bits: 128, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: alg.into(), + }, + }; + let my_key = key_management::import(attributes, None, &key[..]).unwrap(); + let mut output_buffer: BufferPlaintext3 = BufferPlaintext3::new(); + + match aead::decrypt( + my_key, + alg, + iv, + ad, + &ciphertext.content[..ciphertext.len], + &mut output_buffer.content, + ) { + Ok(_) => { + output_buffer.len = ciphertext.len - AES_CCM_TAG_LEN; + Ok(output_buffer) + } + Err(_) => Err(EDHOCError::MacVerificationFailed), + } + } -pub fn aes_ccm_encrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - plaintext: &BufferPlaintext3, -) -> BufferCiphertext3 { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_encrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key[..]).unwrap(); - let mut output_buffer: BufferCiphertext3 = BufferCiphertext3::new(); - - aead::encrypt( - my_key, - alg, - iv, - ad, - &plaintext.content[..plaintext.len], - &mut output_buffer.content, - ) - .unwrap(); - - output_buffer.len = plaintext.len + AES_CCM_TAG_LEN; - output_buffer -} + fn p256_ecdh( + &mut self, + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, + ) -> BytesP256ElemLen { + let mut peer_public_key: [u8; 33] = [0; 33]; + peer_public_key[0] = 0x02; // sign does not matter for ECDH operation + peer_public_key[1..33].copy_from_slice(&public_key[..]); + + let alg = RawKeyAgreement::Ecdh; + let mut usage_flags: UsageFlags = Default::default(); + usage_flags.set_derive(); + let attributes = Attributes { + key_type: Type::EccKeyPair { + curve_family: EccFamily::SecpR1, + }, + bits: 256, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: KeyAgreement::Raw(alg).into(), + }, + }; + + psa_crypto::init().unwrap(); + let my_key = key_management::import(attributes, None, private_key).unwrap(); + let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; + + key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer) + .unwrap(); + + output_buffer + } -pub fn aes_ccm_decrypt_tag_8( - key: &BytesCcmKeyLen, - iv: &BytesCcmIvLen, - ad: &BytesEncStructureLen, - ciphertext: &BufferCiphertext3, -) -> Result { - psa_crypto::init().unwrap(); - - let alg = Aead::AeadWithShortenedTag { - aead_alg: AeadWithDefaultLengthTag::Ccm, - tag_length: 8, - }; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_decrypt(); - - let attributes = Attributes { - key_type: Type::Aes, - bits: 128, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: alg.into(), - }, - }; - let my_key = key_management::import(attributes, None, &key[..]).unwrap(); - let mut output_buffer: BufferPlaintext3 = BufferPlaintext3::new(); - - match aead::decrypt( - my_key, - alg, - iv, - ad, - &ciphertext.content[..ciphertext.len], - &mut output_buffer.content, - ) { - Ok(_) => { - output_buffer.len = ciphertext.len - AES_CCM_TAG_LEN; - Ok(output_buffer) - } - Err(_) => Err(EDHOCError::MacVerificationFailed), + fn get_random_byte(&mut self) -> u8 { + psa_crypto::init().unwrap(); + let mut buffer = [0u8; 1]; + generate_random(&mut buffer); // TODO: check return value + buffer[0] } -} -pub fn p256_ecdh( - private_key: &BytesP256ElemLen, - public_key: &BytesP256ElemLen, -) -> BytesP256ElemLen { - let mut peer_public_key: [u8; 33] = [0; 33]; - peer_public_key[0] = 0x02; // sign does not matter for ECDH operation - peer_public_key[1..33].copy_from_slice(&public_key[..]); - - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = Default::default(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - let my_key = key_management::import(attributes, None, private_key).unwrap(); - let mut output_buffer: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - - key_agreement::raw_key_agreement(alg, my_key, &peer_public_key, &mut output_buffer).unwrap(); - - output_buffer + fn p256_generate_key_pair(&mut self) -> (BytesP256ElemLen, BytesP256ElemLen) { + let alg = RawKeyAgreement::Ecdh; + let mut usage_flags: UsageFlags = UsageFlags::default(); + usage_flags.set_export(); + usage_flags.set_derive(); + let attributes = Attributes { + key_type: Type::EccKeyPair { + curve_family: EccFamily::SecpR1, + }, + bits: 256, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags, + permitted_algorithms: KeyAgreement::Raw(alg).into(), + }, + }; + + psa_crypto::init().unwrap(); + + let key_id = key_management::generate(attributes, None).unwrap(); + let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; + key_management::export(key_id, &mut private_key).unwrap(); + + let mut public_key: [u8; P256_ELEM_LEN * 2 + 1] = [0; P256_ELEM_LEN * 2 + 1]; // allocate buffer for: sign, x, and y coordinates + key_management::export_public(key_id, &mut public_key).unwrap(); + let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // return only the x coordinate + + (private_key, public_key) + } } -pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLen { +fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLen { // implementation of HMAC as per RFC2104 const IPAD: [u8; 64] = [0x36; 64]; @@ -217,7 +268,7 @@ pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLe s2[64..64 + message.len()].copy_from_slice(message); // (4) apply H to the stream generated in step (3) - let ih = sha256_digest(&s2, 64 + message.len()); + let ih = Crypto.sha256_digest(&s2, 64 + message.len()); // (5) XOR (bitwise exclusive-OR) the B byte string computed in // step (1) with opad @@ -231,48 +282,11 @@ pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLe // (7) apply H to the stream generated in step (6) and output // the result - let oh = sha256_digest(&s5, 3 * SHA256_DIGEST_LEN); + let oh = Crypto.sha256_digest(&s5, 3 * SHA256_DIGEST_LEN); oh } -pub fn get_random_byte() -> u8 { - psa_crypto::init().unwrap(); - let mut buffer = [0u8; 1]; - generate_random(&mut buffer); // TODO: check return value - buffer[0] -} - -pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) { - let alg = RawKeyAgreement::Ecdh; - let mut usage_flags: UsageFlags = UsageFlags::default(); - usage_flags.set_export(); - usage_flags.set_derive(); - let attributes = Attributes { - key_type: Type::EccKeyPair { - curve_family: EccFamily::SecpR1, - }, - bits: 256, - lifetime: Lifetime::Volatile, - policy: Policy { - usage_flags, - permitted_algorithms: KeyAgreement::Raw(alg).into(), - }, - }; - - psa_crypto::init().unwrap(); - - let key_id = key_management::generate(attributes, None).unwrap(); - let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN]; - key_management::export(key_id, &mut private_key).unwrap(); - - let mut public_key: [u8; P256_ELEM_LEN * 2 + 1] = [0; P256_ELEM_LEN * 2 + 1]; // allocate buffer for: sign, x, and y coordinates - key_management::export_public(key_id, &mut public_key).unwrap(); - let public_key: [u8; P256_ELEM_LEN] = public_key[1..33].try_into().unwrap(); // return only the x coordinate - - (private_key, public_key) -} - #[cfg(test)] mod tests { use super::*; diff --git a/crypto/edhoc-crypto-trait/Cargo.toml b/crypto/edhoc-crypto-trait/Cargo.toml new file mode 100644 index 00000000..9f02aaba --- /dev/null +++ b/crypto/edhoc-crypto-trait/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "edhoc-crypto-trait" +version = "0.1.0" +edition = "2021" + +[dependencies] +edhoc-consts = { path = "../../consts", default-features = false } diff --git a/crypto/edhoc-crypto-trait/src/lib.rs b/crypto/edhoc-crypto-trait/src/lib.rs new file mode 100644 index 00000000..a3030c4c --- /dev/null +++ b/crypto/edhoc-crypto-trait/src/lib.rs @@ -0,0 +1,37 @@ +//! Cryptography trait back-end for the edhoc-crypto crate +#![no_std] + +use edhoc_consts::*; + +pub trait Crypto { + fn sha256_digest(&mut self, message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen; + fn hkdf_expand( + &mut self, + prk: &BytesHashLen, + info: &BytesMaxInfoBuffer, + info_len: usize, + length: usize, + ) -> BytesMaxBuffer; + fn hkdf_extract(&mut self, salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen; + fn aes_ccm_encrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + plaintext: &BufferPlaintext3, + ) -> BufferCiphertext3; + fn aes_ccm_decrypt_tag_8( + &mut self, + key: &BytesCcmKeyLen, + iv: &BytesCcmIvLen, + ad: &BytesEncStructureLen, + ciphertext: &BufferCiphertext3, + ) -> Result; + fn p256_ecdh( + &mut self, + private_key: &BytesP256ElemLen, + public_key: &BytesP256ElemLen, + ) -> BytesP256ElemLen; + fn get_random_byte(&mut self) -> u8; + fn p256_generate_key_pair(&mut self) -> (BytesP256ElemLen, BytesP256ElemLen); +} diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 5c300559..09e0f6b6 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -1,13 +1,49 @@ +//! Cryptography dispatch for the edhoc-rs crate +//! +//! This crate is used by edhoc-rs to decide which cryptographic back-end to use. Its presence +//! avoids the need for all edhoc-rs types to be generic over a back-end, which would then be +//! provided by the user at initialization time. On the long run, its type may turn into a +//! default associated type. #![no_std] +/// Convenience re-export +pub use edhoc_crypto_trait::Crypto as CryptoTrait; + +#[cfg(feature = "hacspec")] +pub type Crypto = edhoc_crypto_hacspec::Crypto; + #[cfg(feature = "hacspec")] -pub use edhoc_crypto_hacspec::*; +pub const fn default_crypto() -> Crypto { + edhoc_crypto_hacspec::Crypto +} +// FIXME: Does not work with crypto-as-trait yet #[cfg(feature = "cc2538")] pub use edhoc_crypto_cc2538::*; #[cfg(any(feature = "psa", feature = "psa-rust",))] -pub use edhoc_crypto_psa::*; +pub type Crypto = edhoc_crypto_psa::Crypto; + +#[cfg(any(feature = "psa", feature = "psa-rust",))] +pub const fn default_crypto() -> Crypto { + edhoc_crypto_psa::Crypto +} #[cfg(any(feature = "cryptocell310", feature = "cryptocell310-rust"))] -pub use edhoc_crypto_cryptocell310::*; +pub type Crypto = edhoc_crypto_cryptocell310::Crypto; + +#[cfg(any(feature = "cryptocell310", feature = "cryptocell310-rust"))] +pub const fn default_crypto() -> Crypto { + edhoc_crypto_cryptocell310::Crypto +} + +/// See test_implements_crypto +#[allow(dead_code)] +fn test_helper() {} + +/// Ensure at build time that whichever type as selected for Crypto actually implements the Crypto +/// trait, and that one is actually defined. +#[allow(dead_code)] +fn test_implements_crypto() { + test_helper::() +} diff --git a/examples/edhoc-rs-no_std/Cargo.toml b/examples/edhoc-rs-no_std/Cargo.toml index 99fac08e..eae4f8a5 100644 --- a/examples/edhoc-rs-no_std/Cargo.toml +++ b/examples/edhoc-rs-no_std/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] edhoc-rs = { path = "../../lib", default-features = false } +edhoc-crypto = { path = "../../crypto", default-features = false } hexlit = "0.5.3" # depend on an allocator diff --git a/examples/edhoc-rs-no_std/src/main.rs b/examples/edhoc-rs-no_std/src/main.rs index 6d543789..a6d02734 100644 --- a/examples/edhoc-rs-no_std/src/main.rs +++ b/examples/edhoc-rs-no_std/src/main.rs @@ -13,6 +13,7 @@ use panic_semihosting as _; #[cfg(feature = "rtt")] use rtt_target::{rprintln as println, rtt_init_print}; +use edhoc_crypto::{default_crypto, CryptoTrait}; use edhoc_rs::*; extern crate alloc; @@ -80,11 +81,11 @@ fn main() -> ! { println!("Test test_new_initiator passed."); fn test_p256_keys() { - let (x, g_x) = p256_generate_key_pair(); - let (y, g_y) = p256_generate_key_pair(); + let (x, g_x) = default_crypto().p256_generate_key_pair(); + let (y, g_y) = default_crypto().p256_generate_key_pair(); - let g_xy = p256_ecdh(&x, &g_y); - let g_yx = p256_ecdh(&y, &g_x); + let g_xy = default_crypto().p256_ecdh(&x, &g_y); + let g_yx = default_crypto().p256_ecdh(&y, &g_x); assert_eq!(g_xy, g_yx); } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index d782b7e6..3514bbbc 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -12,6 +12,7 @@ hex = { version = "0.4.3", default-features = false } hacspec-lib = { version = "0.1.0-beta.1", default-features = false, optional = true } edhoc-crypto = { path = "../crypto", default-features = false } +edhoc-crypto-trait = { path = "../crypto/edhoc-crypto-trait" } edhoc-consts = { path = "../consts" } edhoc-ead = { path = "../ead", default-features = false } panic-semihosting = { version = "0.6.0", features = ["exit"], optional = true } diff --git a/lib/src/c_wrapper.rs b/lib/src/c_wrapper.rs index b22f672f..a6a7be0f 100644 --- a/lib/src/c_wrapper.rs +++ b/lib/src/c_wrapper.rs @@ -3,6 +3,8 @@ use core::{slice, str}; use edhoc_consts::*; use hexlit::hex; +use edhoc_crypto::{default_crypto, CryptoTrait}; + // Panic handler for cortex-m targets #[cfg(any(feature = "crypto-cryptocell310", feature = "crypto-psa-baremetal"))] use panic_semihosting as _; @@ -10,7 +12,7 @@ use panic_semihosting as _; // This function is mainly used to test the C wrapper #[no_mangle] pub extern "C" fn p256_generate_key_pair_from_c(out_private_key: *mut u8, out_public_key: *mut u8) { - let (private_key, public_key) = edhoc_crypto::p256_generate_key_pair(); + let (private_key, public_key) = default_crypto().p256_generate_key_pair(); unsafe { // copy the arrays to the pointers received from C diff --git a/lib/src/edhoc.rs b/lib/src/edhoc.rs index 9a4dc799..3c8d3ecf 100644 --- a/lib/src/edhoc.rs +++ b/lib/src/edhoc.rs @@ -1,11 +1,12 @@ #![no_std] use edhoc_consts::*; -use edhoc_crypto::*; +use edhoc_crypto_trait::Crypto as CryptoTrait; use edhoc_ead::*; -pub fn edhoc_exporter( +pub fn edhoc_exporter( state: State, + crypto: &mut Crypto, label: u8, context: &BytesMaxContextBuffer, context_len: usize, @@ -28,15 +29,16 @@ pub fn edhoc_exporter( let mut error = EDHOCError::UnknownError; if current_state == EDHOCState::Completed { - output = edhoc_kdf(&prk_exporter, label, context, context_len, length); + output = crypto.edhoc_kdf(&prk_exporter, label, context, context_len, length); Ok((state, output)) } else { Err(EDHOCError::WrongState) } } -pub fn edhoc_key_update( +pub fn edhoc_key_update( mut state: State, + crypto: &mut Crypto, context: &BytesMaxContextBuffer, context_len: usize, ) -> Result<(State, BytesHashLen), EDHOCError> { @@ -58,11 +60,11 @@ pub fn edhoc_key_update( if current_state == EDHOCState::Completed { // new PRK_out - prk_new_buf = edhoc_kdf(&prk_out, 11u8, context, context_len, SHA256_DIGEST_LEN); + prk_new_buf = crypto.edhoc_kdf(&prk_out, 11u8, context, context_len, SHA256_DIGEST_LEN); prk_out[..SHA256_DIGEST_LEN].copy_from_slice(&prk_new_buf[..SHA256_DIGEST_LEN]); // new PRK_exporter - prk_new_buf = edhoc_kdf( + prk_new_buf = crypto.edhoc_kdf( &prk_out, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], @@ -90,8 +92,9 @@ pub fn edhoc_key_update( } } -pub fn r_process_message_1( +pub fn r_process_message_1( mut state: State, + crypto: &mut Crypto, message_1: &BufferMessage1, ) -> Result { let State( @@ -131,7 +134,7 @@ pub fn r_process_message_1( let mut message_1_buf: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; message_1_buf[..message_1.len] .copy_from_slice(&message_1.content[..message_1.len]); - h_message_1 = sha256_digest(&message_1_buf, message_1.len); + h_message_1 = crypto.sha256_digest(&message_1_buf, message_1.len); error = EDHOCError::Success; current_state = EDHOCState::ProcessedMessage1; @@ -170,8 +173,9 @@ pub fn r_process_message_1( } } -pub fn r_prepare_message_2( +pub fn r_prepare_message_2( mut state: State, + crypto: &mut Crypto, id_cred_r: &BytesIdCred, cred_r: &[u8], r: &BytesP256ElemLen, // R's static private DH key @@ -197,15 +201,15 @@ pub fn r_prepare_message_2( if current_state == EDHOCState::ProcessedMessage1 { // compute TH_2 - let th_2 = compute_th_2(&g_y, &h_message_1); + let th_2 = crypto.compute_th_2(&g_y, &h_message_1); // compute prk_3e2m - let prk_2e = compute_prk_2e(&y, &g_x, &th_2); - let salt_3e2m = compute_salt_3e2m(&prk_2e, &th_2); - prk_3e2m = compute_prk_3e2m(&salt_3e2m, r, &g_x); + let prk_2e = crypto.compute_prk_2e(&y, &g_x, &th_2); + let salt_3e2m = crypto.compute_salt_3e2m(&prk_2e, &th_2); + prk_3e2m = crypto.compute_prk_3e2m(&salt_3e2m, r, &g_x); // compute MAC_2 - let mac_2 = compute_mac_2(&prk_3e2m, id_cred_r, cred_r, &th_2); + let mac_2 = crypto.compute_mac_2(&prk_3e2m, id_cred_r, cred_r, &th_2); let ead_2 = r_prepare_ead_2(); @@ -214,13 +218,14 @@ pub fn r_prepare_message_2( // step is actually from processing of message_3 // but we do it here to avoid storing plaintext_2 in State - th_3 = compute_th_3(&th_2, &plaintext_2, cred_r); + th_3 = crypto.compute_th_3(&th_2, &plaintext_2, cred_r); let mut ct: BufferCiphertext2 = BufferCiphertext2::new(); ct.len = plaintext_2.len; ct.content[..ct.len].copy_from_slice(&plaintext_2.content[..ct.len]); - let (ciphertext_2, ciphertext_2_len) = encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &ct); + let (ciphertext_2, ciphertext_2_len) = + crypto.encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &ct); ct.content[..ct.len].copy_from_slice(&ciphertext_2[..ct.len]); @@ -252,8 +257,9 @@ pub fn r_prepare_message_2( } // FIXME fetch ID_CRED_I and CRED_I based on kid -pub fn r_process_message_3( +pub fn r_process_message_3( mut state: State, + crypto: &mut Crypto, message_3: &BufferMessage3, id_cred_i_expected: &BytesIdCred, cred_i_expected: &[u8], @@ -275,7 +281,7 @@ pub fn r_process_message_3( let mut error = EDHOCError::UnknownError; if current_state == EDHOCState::WaitMessage3 { - let plaintext_3 = decrypt_message_3(&prk_3e2m, &th_3, message_3); + let plaintext_3 = crypto.decrypt_message_3(&prk_3e2m, &th_3, message_3); if plaintext_3.is_ok() { let plaintext_3 = plaintext_3.unwrap(); @@ -294,31 +300,40 @@ pub fn r_process_message_3( // compare the kid received with the kid expected in id_cred_i if kid == id_cred_i_expected[id_cred_i_expected.len() - 1] { // compute salt_4e3m - let salt_4e3m = compute_salt_4e3m(&prk_3e2m, &th_3); + let salt_4e3m = crypto.compute_salt_4e3m(&prk_3e2m, &th_3); // TODO compute prk_4e3m - prk_4e3m = compute_prk_4e3m(&salt_4e3m, &y, g_i); + prk_4e3m = crypto.compute_prk_4e3m(&salt_4e3m, &y, g_i); // compute mac_3 - let expected_mac_3 = - compute_mac_3(&prk_4e3m, &th_3, id_cred_i_expected, cred_i_expected); + let expected_mac_3 = crypto.compute_mac_3( + &prk_4e3m, + &th_3, + id_cred_i_expected, + cred_i_expected, + ); // verify mac_3 if mac_3 == expected_mac_3 { error = EDHOCError::Success; - let th_4 = compute_th_4(&th_3, &plaintext_3, cred_i_expected); + let th_4 = crypto.compute_th_4(&th_3, &plaintext_3, cred_i_expected); let mut th_4_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; th_4_buf[..th_4.len()].copy_from_slice(&th_4[..]); // compute prk_out // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let prk_out_buf = - edhoc_kdf(&prk_4e3m, 7u8, &th_4_buf, th_4.len(), SHA256_DIGEST_LEN); + let prk_out_buf = crypto.edhoc_kdf( + &prk_4e3m, + 7u8, + &th_4_buf, + th_4.len(), + SHA256_DIGEST_LEN, + ); prk_out[..SHA256_DIGEST_LEN] .copy_from_slice(&prk_out_buf[..SHA256_DIGEST_LEN]); // compute prk_exporter from prk_out // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let prk_exporter_buf = edhoc_kdf( + let prk_exporter_buf = crypto.edhoc_kdf( &prk_out, 10u8, &[0x00u8; MAX_KDF_CONTEXT_LEN], @@ -369,8 +384,9 @@ pub fn r_process_message_3( } } -pub fn i_prepare_message_1( +pub fn i_prepare_message_1( mut state: State, + crypto: &mut Crypto, x: BytesP256ElemLen, g_x: BytesP256ElemLen, c_i: u8, @@ -413,7 +429,7 @@ pub fn i_prepare_message_1( message_1_buf[..message_1.len].copy_from_slice(&message_1.content[..message_1.len]); // hash message_1 here to avoid saving the whole message in the state - h_message_1 = sha256_digest(&message_1_buf, message_1.len); + h_message_1 = crypto.sha256_digest(&message_1_buf, message_1.len); error = EDHOCError::Success; current_state = EDHOCState::WaitMessage2; @@ -440,8 +456,9 @@ pub fn i_prepare_message_1( } // returns c_r -pub fn i_process_message_2( +pub fn i_process_message_2( mut state: State, + crypto: &mut Crypto, message_2: &BufferMessage2, id_cred_r_expected: &BytesIdCred, cred_r_expected: &[u8], @@ -471,13 +488,13 @@ pub fn i_process_message_2( if res.is_ok() { let (g_y, ciphertext_2) = res.unwrap(); - let th_2 = compute_th_2(&g_y, &h_message_1); + let th_2 = crypto.compute_th_2(&g_y, &h_message_1); // compute prk_2e - let prk_2e = compute_prk_2e(&x, &g_y, &th_2); + let prk_2e = crypto.compute_prk_2e(&x, &g_y, &th_2); let (plaintext_2, plaintext_2_len) = - encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &ciphertext_2); + crypto.encrypt_decrypt_ciphertext_2(&prk_2e, &th_2, &ciphertext_2); // decode plaintext_2 let plaintext_2_decoded = decode_plaintext_2(&plaintext_2, plaintext_2_len); @@ -494,12 +511,12 @@ pub fn i_process_message_2( }; if ead_success { // verify mac_2 - let salt_3e2m = compute_salt_3e2m(&prk_2e, &th_2); + let salt_3e2m = crypto.compute_salt_3e2m(&prk_2e, &th_2); - prk_3e2m = compute_prk_3e2m(&salt_3e2m, &x, g_r); + prk_3e2m = crypto.compute_prk_3e2m(&salt_3e2m, &x, g_r); let expected_mac_2 = - compute_mac_2(&prk_3e2m, id_cred_r_expected, cred_r_expected, &th_2); + crypto.compute_mac_2(&prk_3e2m, id_cred_r_expected, cred_r_expected, &th_2); if mac_2 == expected_mac_2 { if kid == id_cred_r_expected[id_cred_r_expected.len() - 1] { @@ -509,12 +526,12 @@ pub fn i_process_message_2( pt2.content[..plaintext_2_len] .copy_from_slice(&plaintext_2[..plaintext_2_len]); pt2.len = plaintext_2_len; - th_3 = compute_th_3(&th_2, &pt2, cred_r_expected); + th_3 = crypto.compute_th_3(&th_2, &pt2, cred_r_expected); // message 3 processing - let salt_4e3m = compute_salt_4e3m(&prk_3e2m, &th_3); + let salt_4e3m = crypto.compute_salt_4e3m(&prk_3e2m, &th_3); - prk_4e3m = compute_prk_4e3m(&salt_4e3m, i, &g_y); + prk_4e3m = crypto.compute_prk_4e3m(&salt_4e3m, i, &g_y); error = EDHOCError::Success; current_state = EDHOCState::ProcessedMessage2; @@ -557,8 +574,9 @@ pub fn i_process_message_2( } } -pub fn i_prepare_message_3( +pub fn i_prepare_message_3( mut state: State, + crypto: &mut Crypto, id_cred_i: &BytesIdCred, cred_i: &[u8], ) -> Result<(State, BufferMessage3, BytesHashLen), EDHOCError> { @@ -579,26 +597,27 @@ pub fn i_prepare_message_3( let mut message_3: BufferMessage3 = BufferMessage3::new(); if current_state == EDHOCState::ProcessedMessage2 { - let mac_3 = compute_mac_3(&prk_4e3m, &th_3, id_cred_i, cred_i); + let mac_3 = crypto.compute_mac_3(&prk_4e3m, &th_3, id_cred_i, cred_i); let ead_3 = i_prepare_ead_3(); let plaintext_3 = encode_plaintext_3(id_cred_i, &mac_3, &ead_3); - message_3 = encrypt_message_3(&prk_3e2m, &th_3, &plaintext_3); + message_3 = crypto.encrypt_message_3(&prk_3e2m, &th_3, &plaintext_3); - let th_4 = compute_th_4(&th_3, &plaintext_3, cred_i); + let th_4 = crypto.compute_th_4(&th_3, &plaintext_3, cred_i); let mut th_4_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; th_4_buf[..th_4.len()].copy_from_slice(&th_4[..]); // compute prk_out // PRK_out = EDHOC-KDF( PRK_4e3m, 7, TH_4, hash_length ) - let prk_out_buf = edhoc_kdf(&prk_4e3m, 7u8, &th_4_buf, th_4.len(), SHA256_DIGEST_LEN); + let prk_out_buf = + crypto.edhoc_kdf(&prk_4e3m, 7u8, &th_4_buf, th_4.len(), SHA256_DIGEST_LEN); prk_out[..SHA256_DIGEST_LEN].copy_from_slice(&prk_out_buf[..SHA256_DIGEST_LEN]); // compute prk_exporter from prk_out // PRK_exporter = EDHOC-KDF( PRK_out, 10, h'', hash_length ) - let prk_exporter_buf = edhoc_kdf( + let prk_exporter_buf = crypto.edhoc_kdf( &prk_out, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], @@ -992,99 +1011,333 @@ fn encode_message_2(g_y: &BytesP256ElemLen, ciphertext_2: &BufferCiphertext2) -> output } -fn compute_th_2(g_y: &BytesP256ElemLen, h_message_1: &BytesHashLen) -> BytesHashLen { - let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; - message[0] = CBOR_BYTE_STRING; - message[1] = P256_ELEM_LEN as u8; - message[2..2 + P256_ELEM_LEN].copy_from_slice(g_y); - message[2 + P256_ELEM_LEN] = CBOR_BYTE_STRING; - message[3 + P256_ELEM_LEN] = SHA256_DIGEST_LEN as u8; - message[4 + P256_ELEM_LEN..4 + P256_ELEM_LEN + SHA256_DIGEST_LEN] - .copy_from_slice(&h_message_1[..]); +// All these functions that are generally pure functions without any state they handle are +// expressed as an extension to the Crypto trait, because this gives the easiest invocation +// semantics -- any code outside them can just call `crypto.compute_th_2()`, code inside calls +// `self.some_function()`. +// +// It's easier to write because it allows the Crypto generics to sit on the trait instead of being +// repeated for each function. (Other than that, they could all just as well be called +// `computed_th_2(crypto, ...)` etc). +trait CryptoExt: CryptoTrait { + fn compute_th_2(&mut self, g_y: &BytesP256ElemLen, h_message_1: &BytesHashLen) -> BytesHashLen { + let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + message[0] = CBOR_BYTE_STRING; + message[1] = P256_ELEM_LEN as u8; + message[2..2 + P256_ELEM_LEN].copy_from_slice(g_y); + message[2 + P256_ELEM_LEN] = CBOR_BYTE_STRING; + message[3 + P256_ELEM_LEN] = SHA256_DIGEST_LEN as u8; + message[4 + P256_ELEM_LEN..4 + P256_ELEM_LEN + SHA256_DIGEST_LEN] + .copy_from_slice(&h_message_1[..]); + + let len = 4 + P256_ELEM_LEN + SHA256_DIGEST_LEN; + + let th_2 = self.sha256_digest(&message, len); + + th_2 + } + + fn compute_th_3( + &mut self, + th_2: &BytesHashLen, + plaintext_2: &BufferPlaintext2, + cred_r: &[u8], + ) -> BytesHashLen { + let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + + message[0] = CBOR_BYTE_STRING; + message[1] = th_2.len() as u8; + message[2..2 + th_2.len()].copy_from_slice(&th_2[..]); + message[2 + th_2.len()..2 + th_2.len() + plaintext_2.len] + .copy_from_slice(&plaintext_2.content[..plaintext_2.len]); + message[2 + th_2.len() + plaintext_2.len..2 + th_2.len() + plaintext_2.len + cred_r.len()] + .copy_from_slice(cred_r); + + let output = self.sha256_digest(&message, th_2.len() + 2 + plaintext_2.len + cred_r.len()); + + output + } + + fn compute_th_4( + &mut self, + th_3: &BytesHashLen, + plaintext_3: &BufferPlaintext3, + cred_i: &[u8], + ) -> BytesHashLen { + let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + + message[0] = CBOR_BYTE_STRING; + message[1] = th_3.len() as u8; + message[2..2 + th_3.len()].copy_from_slice(&th_3[..]); + message[2 + th_3.len()..2 + th_3.len() + plaintext_3.len] + .copy_from_slice(&plaintext_3.content[..plaintext_3.len]); + message[2 + th_3.len() + plaintext_3.len..2 + th_3.len() + plaintext_3.len + cred_i.len()] + .copy_from_slice(cred_i); + + let output = self.sha256_digest(&message, th_3.len() + 2 + plaintext_3.len + cred_i.len()); + + output + } + + fn edhoc_kdf( + &mut self, + prk: &BytesHashLen, + label: u8, + context: &BytesMaxContextBuffer, + context_len: usize, + length: usize, + ) -> BytesMaxBuffer { + let mut info: BytesMaxInfoBuffer = [0x00; MAX_INFO_LEN]; + let mut info_len = 0; + + // construct info with inline cbor encoding + info[0] = label; + if context_len < 24 { + info[1] = context_len as u8 | CBOR_MAJOR_BYTE_STRING; + info[2..2 + context_len].copy_from_slice(&context[..context_len]); + info_len = 2 + context_len; + } else { + info[1] = CBOR_BYTE_STRING; + info[2] = context_len as u8; + info[3..3 + context_len].copy_from_slice(&context[..context_len]); + info_len = 3 + context_len; + } + if length < 24 { + info[info_len] = length as u8; + info_len = info_len + 1; + } else { + info[info_len] = CBOR_UINT_1BYTE; + info[info_len + 1] = length as u8; + info_len = info_len + 2; + } - let len = 4 + P256_ELEM_LEN + SHA256_DIGEST_LEN; + let output = self.hkdf_expand(prk, &info, info_len, length); - let th_2 = sha256_digest(&message, len); + output + } - th_2 -} + fn compute_k_3_iv_3( + &mut self, + prk_3e2m: &BytesHashLen, + th_3: &BytesHashLen, + ) -> (BytesCcmKeyLen, BytesCcmIvLen) { + // K_3 = EDHOC-KDF( PRK_3e2m, 3, TH_3, key_length ) + let mut k_3: BytesCcmKeyLen = [0x00; AES_CCM_KEY_LEN]; + let mut th_3_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; + th_3_buf[..th_3.len()].copy_from_slice(&th_3[..]); + let k_3_buf = self.edhoc_kdf(prk_3e2m, 3u8, &th_3_buf, th_3.len(), AES_CCM_KEY_LEN); + k_3[..].copy_from_slice(&k_3_buf[..AES_CCM_KEY_LEN]); -fn compute_th_3( - th_2: &BytesHashLen, - plaintext_2: &BufferPlaintext2, - cred_r: &[u8], -) -> BytesHashLen { - let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + // IV_3 = EDHOC-KDF( PRK_3e2m, 4, TH_3, iv_length ) + let mut iv_3: BytesCcmIvLen = [0x00; AES_CCM_IV_LEN]; + let iv_3_buf = self.edhoc_kdf(prk_3e2m, 4u8, &th_3_buf, th_3.len(), AES_CCM_IV_LEN); + iv_3[..].copy_from_slice(&iv_3_buf[..AES_CCM_IV_LEN]); - message[0] = CBOR_BYTE_STRING; - message[1] = th_2.len() as u8; - message[2..2 + th_2.len()].copy_from_slice(&th_2[..]); - message[2 + th_2.len()..2 + th_2.len() + plaintext_2.len] - .copy_from_slice(&plaintext_2.content[..plaintext_2.len]); - message[2 + th_2.len() + plaintext_2.len..2 + th_2.len() + plaintext_2.len + cred_r.len()] - .copy_from_slice(cred_r); + (k_3, iv_3) + } - let output = sha256_digest(&message, th_2.len() + 2 + plaintext_2.len + cred_r.len()); + // calculates ciphertext_3 wrapped in a cbor byte string + fn encrypt_message_3( + &mut self, + prk_3e2m: &BytesHashLen, + th_3: &BytesHashLen, + plaintext_3: &BufferPlaintext3, + ) -> BufferMessage3 { + let mut output: BufferMessage3 = BufferMessage3::new(); + output.len = 1 + plaintext_3.len + AES_CCM_TAG_LEN; + output.content[0] = CBOR_MAJOR_BYTE_STRING | (plaintext_3.len + AES_CCM_TAG_LEN) as u8; // FIXME if plaintext_3.len + AES_CCM_TAG_LEN > 23, then should use CBOR_BYTE_STRING - output -} + let enc_structure = encode_enc_structure(th_3); -fn compute_th_4( - th_3: &BytesHashLen, - plaintext_3: &BufferPlaintext3, - cred_i: &[u8], -) -> BytesHashLen { - let mut message: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + let (k_3, iv_3) = self.compute_k_3_iv_3(prk_3e2m, th_3); - message[0] = CBOR_BYTE_STRING; - message[1] = th_3.len() as u8; - message[2..2 + th_3.len()].copy_from_slice(&th_3[..]); - message[2 + th_3.len()..2 + th_3.len() + plaintext_3.len] - .copy_from_slice(&plaintext_3.content[..plaintext_3.len]); - message[2 + th_3.len() + plaintext_3.len..2 + th_3.len() + plaintext_3.len + cred_i.len()] - .copy_from_slice(cred_i); + let ciphertext_3 = self.aes_ccm_encrypt_tag_8(&k_3, &iv_3, &enc_structure, plaintext_3); - let output = sha256_digest(&message, th_3.len() + 2 + plaintext_3.len + cred_i.len()); + output.content[1..output.len].copy_from_slice(&ciphertext_3.content[..ciphertext_3.len]); - output -} + output + } -fn edhoc_kdf( - prk: &BytesHashLen, - label: u8, - context: &BytesMaxContextBuffer, - context_len: usize, - length: usize, -) -> BytesMaxBuffer { - let mut info: BytesMaxInfoBuffer = [0x00; MAX_INFO_LEN]; - let mut info_len = 0; - - // construct info with inline cbor encoding - info[0] = label; - if context_len < 24 { - info[1] = context_len as u8 | CBOR_MAJOR_BYTE_STRING; - info[2..2 + context_len].copy_from_slice(&context[..context_len]); - info_len = 2 + context_len; - } else { - info[1] = CBOR_BYTE_STRING; - info[2] = context_len as u8; - info[3..3 + context_len].copy_from_slice(&context[..context_len]); - info_len = 3 + context_len; - } - if length < 24 { - info[info_len] = length as u8; - info_len = info_len + 1; - } else { - info[info_len] = CBOR_UINT_1BYTE; - info[info_len + 1] = length as u8; - info_len = info_len + 2; + fn decrypt_message_3( + &mut self, + prk_3e2m: &BytesHashLen, + th_3: &BytesHashLen, + message_3: &BufferMessage3, + ) -> Result { + let mut error = EDHOCError::UnknownError; + let mut plaintext_3: BufferPlaintext3 = BufferPlaintext3::new(); + + // decode message_3 + let len = (message_3.content[0usize] ^ CBOR_MAJOR_BYTE_STRING) as usize; + + let mut ciphertext_3: BufferCiphertext3 = BufferCiphertext3::new(); + ciphertext_3.len = len; + ciphertext_3.content[..len].copy_from_slice(&message_3.content[1..1 + len]); + + let (k_3, iv_3) = self.compute_k_3_iv_3(prk_3e2m, th_3); + + let enc_structure = encode_enc_structure(th_3); + + let p3 = self.aes_ccm_decrypt_tag_8(&k_3, &iv_3, &enc_structure, &ciphertext_3); + + if p3.is_ok() { + error = EDHOCError::Success; + let p3 = p3.unwrap(); + plaintext_3.content[..p3.len].copy_from_slice(&p3.content[..p3.len]); + plaintext_3.len = p3.len; + } else { + error = p3.unwrap_err(); + } + + match error { + EDHOCError::Success => Ok(plaintext_3), + _ => Err(error), + } } - let output = hkdf_expand(prk, &info, info_len, length); + fn compute_mac_3( + &mut self, + prk_4e3m: &BytesHashLen, + th_3: &BytesHashLen, + id_cred_i: &BytesIdCred, + cred_i: &[u8], + ) -> BytesMac3 { + // MAC_3 = EDHOC-KDF( PRK_4e3m, 6, context_3, mac_length_3 ) + let (context, context_len) = encode_kdf_context(id_cred_i, th_3, cred_i); - output + // compute mac_3 + let output_buf = self.edhoc_kdf( + prk_4e3m, + 6u8, // registered label for "MAC_3" + &context, + context_len, + MAC_LENGTH_3, + ); + + let mut output: BytesMac3 = [0x00; MAC_LENGTH_3]; + output[..MAC_LENGTH_3].copy_from_slice(&output_buf[..MAC_LENGTH_3]); + output + } + + fn compute_mac_2( + &mut self, + prk_3e2m: &BytesHashLen, + id_cred_r: &BytesIdCred, + cred_r: &[u8], + th_2: &BytesHashLen, + ) -> BytesMac2 { + // compute MAC_2 + let (context, context_len) = encode_kdf_context(id_cred_r, th_2, cred_r); + + // MAC_2 = EDHOC-KDF( PRK_3e2m, 2, context_2, mac_length_2 ) + let mut mac_2: BytesMac2 = [0x00; MAC_LENGTH_2]; + mac_2[..].copy_from_slice( + &self.edhoc_kdf(prk_3e2m, 2 as u8, &context, context_len, MAC_LENGTH_2)[..MAC_LENGTH_2], + ); + + mac_2 + } + + fn encrypt_decrypt_ciphertext_2( + &mut self, + prk_2e: &BytesHashLen, + th_2: &BytesHashLen, + ciphertext_2: &BufferCiphertext2, + ) -> (BytesMaxBuffer, usize) { + // convert the transcript hash th_2 to BytesMaxContextBuffer type + let mut th_2_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; + th_2_context[..th_2.len()].copy_from_slice(&th_2[..]); + + // KEYSTREAM_2 = EDHOC-KDF( PRK_2e, 0, TH_2, plaintext_length ) + let keystream_2 = self.edhoc_kdf( + prk_2e, + 0u8, + &th_2_context, + SHA256_DIGEST_LEN, + ciphertext_2.len, + ); + + let mut plaintext_2: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; + // decrypt/encrypt ciphertext_2 + for i in 0..ciphertext_2.len { + plaintext_2[i] = ciphertext_2.content[i] ^ keystream_2[i]; + } + + (plaintext_2, ciphertext_2.len) + } + + fn compute_salt_4e3m(&mut self, prk_3e2m: &BytesHashLen, th_3: &BytesHashLen) -> BytesHashLen { + let mut th_3_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; + th_3_context[..th_3.len()].copy_from_slice(&th_3[..]); + let salt_4e3m_buf = + self.edhoc_kdf(prk_3e2m, 5u8, &th_3_context, th_3.len(), SHA256_DIGEST_LEN); + let mut salt_4e3m: BytesHashLen = [0x00; SHA256_DIGEST_LEN]; + salt_4e3m[..].copy_from_slice(&salt_4e3m_buf[..SHA256_DIGEST_LEN]); + + salt_4e3m + } + + fn compute_prk_4e3m( + &mut self, + salt_4e3m: &BytesHashLen, + i: &BytesP256ElemLen, + g_y: &BytesP256ElemLen, + ) -> BytesHashLen { + // compute g_rx from static R's public key and private ephemeral key + let g_iy = self.p256_ecdh(i, g_y); + let prk_4e3m = self.hkdf_extract(salt_4e3m, &g_iy); + + prk_4e3m + } + + fn compute_salt_3e2m(&mut self, prk_2e: &BytesHashLen, th_2: &BytesHashLen) -> BytesHashLen { + let mut th_2_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; + th_2_context[..th_2.len()].copy_from_slice(&th_2[..]); + + let salt_3e2m_buf = self.edhoc_kdf( + prk_2e, + 1u8, + &th_2_context, + SHA256_DIGEST_LEN, + SHA256_DIGEST_LEN, + ); + + let mut salt_3e2m: BytesHashLen = [0x00; SHA256_DIGEST_LEN]; + salt_3e2m[..].copy_from_slice(&salt_3e2m_buf[..SHA256_DIGEST_LEN]); + + salt_3e2m + } + + fn compute_prk_3e2m( + &mut self, + salt_3e2m: &BytesHashLen, + x: &BytesP256ElemLen, + g_r: &BytesP256ElemLen, + ) -> BytesHashLen { + // compute g_rx from static R's public key and private ephemeral key + let g_rx = self.p256_ecdh(x, g_r); + let prk_3e2m = self.hkdf_extract(salt_3e2m, &g_rx); + + prk_3e2m + } + + fn compute_prk_2e( + &mut self, + x: &BytesP256ElemLen, + g_y: &BytesP256ElemLen, + th_2: &BytesHashLen, + ) -> BytesHashLen { + // compute the shared secret + let g_xy = self.p256_ecdh(x, g_y); + // compute prk_2e as PRK_2e = HMAC-SHA-256( salt, G_XY ) + let prk_2e = self.hkdf_extract(th_2, &g_xy); + + prk_2e + } } +impl CryptoExt for Crypto {} + fn decode_plaintext_3( plaintext_3: &BufferPlaintext3, ) -> Result<(u8, BytesMac3, Option), EDHOCError> { @@ -1175,82 +1428,6 @@ fn encode_enc_structure(th_3: &BytesHashLen) -> BytesEncStructureLen { enc_structure } -fn compute_k_3_iv_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, -) -> (BytesCcmKeyLen, BytesCcmIvLen) { - // K_3 = EDHOC-KDF( PRK_3e2m, 3, TH_3, key_length ) - let mut k_3: BytesCcmKeyLen = [0x00; AES_CCM_KEY_LEN]; - let mut th_3_buf: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; - th_3_buf[..th_3.len()].copy_from_slice(&th_3[..]); - let k_3_buf = edhoc_kdf(prk_3e2m, 3u8, &th_3_buf, th_3.len(), AES_CCM_KEY_LEN); - k_3[..].copy_from_slice(&k_3_buf[..AES_CCM_KEY_LEN]); - - // IV_3 = EDHOC-KDF( PRK_3e2m, 4, TH_3, iv_length ) - let mut iv_3: BytesCcmIvLen = [0x00; AES_CCM_IV_LEN]; - let iv_3_buf = edhoc_kdf(prk_3e2m, 4u8, &th_3_buf, th_3.len(), AES_CCM_IV_LEN); - iv_3[..].copy_from_slice(&iv_3_buf[..AES_CCM_IV_LEN]); - - (k_3, iv_3) -} - -// calculates ciphertext_3 wrapped in a cbor byte string -fn encrypt_message_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, - plaintext_3: &BufferPlaintext3, -) -> BufferMessage3 { - let mut output: BufferMessage3 = BufferMessage3::new(); - output.len = 1 + plaintext_3.len + AES_CCM_TAG_LEN; - output.content[0] = CBOR_MAJOR_BYTE_STRING | (plaintext_3.len + AES_CCM_TAG_LEN) as u8; // FIXME if plaintext_3.len + AES_CCM_TAG_LEN > 23, then should use CBOR_BYTE_STRING - - let enc_structure = encode_enc_structure(th_3); - - let (k_3, iv_3) = compute_k_3_iv_3(prk_3e2m, th_3); - - let ciphertext_3 = aes_ccm_encrypt_tag_8(&k_3, &iv_3, &enc_structure, plaintext_3); - - output.content[1..output.len].copy_from_slice(&ciphertext_3.content[..ciphertext_3.len]); - - output -} - -fn decrypt_message_3( - prk_3e2m: &BytesHashLen, - th_3: &BytesHashLen, - message_3: &BufferMessage3, -) -> Result { - let mut error = EDHOCError::UnknownError; - let mut plaintext_3: BufferPlaintext3 = BufferPlaintext3::new(); - - // decode message_3 - let len = (message_3.content[0usize] ^ CBOR_MAJOR_BYTE_STRING) as usize; - - let mut ciphertext_3: BufferCiphertext3 = BufferCiphertext3::new(); - ciphertext_3.len = len; - ciphertext_3.content[..len].copy_from_slice(&message_3.content[1..1 + len]); - - let (k_3, iv_3) = compute_k_3_iv_3(prk_3e2m, th_3); - - let enc_structure = encode_enc_structure(th_3); - - let p3 = aes_ccm_decrypt_tag_8(&k_3, &iv_3, &enc_structure, &ciphertext_3); - - if p3.is_ok() { - error = EDHOCError::Success; - let p3 = p3.unwrap(); - plaintext_3.content[..p3.len].copy_from_slice(&p3.content[..p3.len]); - plaintext_3.len = p3.len; - } else { - error = p3.unwrap_err(); - } - - match error { - EDHOCError::Success => Ok(plaintext_3), - _ => Err(error), - } -} - // output must hold id_cred.len() + cred.len() fn encode_kdf_context( id_cred: &BytesIdCred, @@ -1272,47 +1449,6 @@ fn encode_kdf_context( (output, output_len) } -fn compute_mac_3( - prk_4e3m: &BytesHashLen, - th_3: &BytesHashLen, - id_cred_i: &BytesIdCred, - cred_i: &[u8], -) -> BytesMac3 { - // MAC_3 = EDHOC-KDF( PRK_4e3m, 6, context_3, mac_length_3 ) - let (context, context_len) = encode_kdf_context(id_cred_i, th_3, cred_i); - - // compute mac_3 - let output_buf = edhoc_kdf( - prk_4e3m, - 6u8, // registered label for "MAC_3" - &context, - context_len, - MAC_LENGTH_3, - ); - - let mut output: BytesMac3 = [0x00; MAC_LENGTH_3]; - output[..MAC_LENGTH_3].copy_from_slice(&output_buf[..MAC_LENGTH_3]); - output -} - -fn compute_mac_2( - prk_3e2m: &BytesHashLen, - id_cred_r: &BytesIdCred, - cred_r: &[u8], - th_2: &BytesHashLen, -) -> BytesMac2 { - // compute MAC_2 - let (context, context_len) = encode_kdf_context(id_cred_r, th_2, cred_r); - - // MAC_2 = EDHOC-KDF( PRK_3e2m, 2, context_2, mac_length_2 ) - let mut mac_2: BytesMac2 = [0x00; MAC_LENGTH_2]; - mac_2[..].copy_from_slice( - &edhoc_kdf(prk_3e2m, 2 as u8, &context, context_len, MAC_LENGTH_2)[..MAC_LENGTH_2], - ); - - mac_2 -} - fn decode_plaintext_2( plaintext_2: &BytesMaxBuffer, plaintext_2_len: usize, @@ -1386,102 +1522,12 @@ fn encode_plaintext_2( plaintext_2 } -fn encrypt_decrypt_ciphertext_2( - prk_2e: &BytesHashLen, - th_2: &BytesHashLen, - ciphertext_2: &BufferCiphertext2, -) -> (BytesMaxBuffer, usize) { - // convert the transcript hash th_2 to BytesMaxContextBuffer type - let mut th_2_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; - th_2_context[..th_2.len()].copy_from_slice(&th_2[..]); - - // KEYSTREAM_2 = EDHOC-KDF( PRK_2e, 0, TH_2, plaintext_length ) - let keystream_2 = edhoc_kdf( - prk_2e, - 0u8, - &th_2_context, - SHA256_DIGEST_LEN, - ciphertext_2.len, - ); - - let mut plaintext_2: BytesMaxBuffer = [0x00; MAX_BUFFER_LEN]; - // decrypt/encrypt ciphertext_2 - for i in 0..ciphertext_2.len { - plaintext_2[i] = ciphertext_2.content[i] ^ keystream_2[i]; - } - - (plaintext_2, ciphertext_2.len) -} - -fn compute_salt_4e3m(prk_3e2m: &BytesHashLen, th_3: &BytesHashLen) -> BytesHashLen { - let mut th_3_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; - th_3_context[..th_3.len()].copy_from_slice(&th_3[..]); - let salt_4e3m_buf = edhoc_kdf(prk_3e2m, 5u8, &th_3_context, th_3.len(), SHA256_DIGEST_LEN); - let mut salt_4e3m: BytesHashLen = [0x00; SHA256_DIGEST_LEN]; - salt_4e3m[..].copy_from_slice(&salt_4e3m_buf[..SHA256_DIGEST_LEN]); - - salt_4e3m -} - -fn compute_prk_4e3m( - salt_4e3m: &BytesHashLen, - i: &BytesP256ElemLen, - g_y: &BytesP256ElemLen, -) -> BytesHashLen { - // compute g_rx from static R's public key and private ephemeral key - let g_iy = p256_ecdh(i, g_y); - let prk_4e3m = hkdf_extract(salt_4e3m, &g_iy); - - prk_4e3m -} - -fn compute_salt_3e2m(prk_2e: &BytesHashLen, th_2: &BytesHashLen) -> BytesHashLen { - let mut th_2_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; - th_2_context[..th_2.len()].copy_from_slice(&th_2[..]); - - let salt_3e2m_buf = edhoc_kdf( - prk_2e, - 1u8, - &th_2_context, - SHA256_DIGEST_LEN, - SHA256_DIGEST_LEN, - ); - - let mut salt_3e2m: BytesHashLen = [0x00; SHA256_DIGEST_LEN]; - salt_3e2m[..].copy_from_slice(&salt_3e2m_buf[..SHA256_DIGEST_LEN]); - - salt_3e2m -} - -fn compute_prk_3e2m( - salt_3e2m: &BytesHashLen, - x: &BytesP256ElemLen, - g_r: &BytesP256ElemLen, -) -> BytesHashLen { - // compute g_rx from static R's public key and private ephemeral key - let g_rx = p256_ecdh(x, g_r); - let prk_3e2m = hkdf_extract(salt_3e2m, &g_rx); - - prk_3e2m -} - -fn compute_prk_2e( - x: &BytesP256ElemLen, - g_y: &BytesP256ElemLen, - th_2: &BytesHashLen, -) -> BytesHashLen { - // compute the shared secret - let g_xy = p256_ecdh(x, g_y); - // compute prk_2e as PRK_2e = HMAC-SHA-256( salt, G_XY ) - let prk_2e = hkdf_extract(th_2, &g_xy); - - prk_2e -} - #[cfg(test)] mod tests { use super::*; use hexlit::hex; + + use edhoc_crypto::default_crypto; // test vectors (TV) // message_1 (first_time) @@ -1590,7 +1636,7 @@ mod tests { #[test] fn test_ecdh() { - let g_xy = p256_ecdh(&X_TV, &G_Y_TV); + let g_xy = default_crypto().p256_ecdh(&X_TV, &G_Y_TV); assert_eq!(g_xy, G_XY_TV); } @@ -1728,7 +1774,7 @@ mod tests { #[test] fn test_compute_th_2() { - let th_2 = compute_th_2(&G_Y_TV, &H_MESSAGE_1_TV); + let th_2 = default_crypto().compute_th_2(&G_Y_TV, &H_MESSAGE_1_TV); assert_eq!(th_2, TH_2_TV); } @@ -1736,7 +1782,7 @@ mod tests { fn test_compute_th_3() { let plaintext_2_tv = BufferPlaintext2::from_hex(PLAINTEXT_2_TV); - let th_3 = compute_th_3(&TH_2_TV, &plaintext_2_tv, &CRED_R_TV); + let th_3 = default_crypto().compute_th_3(&TH_2_TV, &plaintext_2_tv, &CRED_R_TV); assert_eq!(th_3, TH_3_TV); } @@ -1744,7 +1790,7 @@ mod tests { fn test_compute_th_4() { let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); - let th_4 = compute_th_4(&TH_3_TV, &plaintext_3_tv, &CRED_I_TV); + let th_4 = default_crypto().compute_th_4(&TH_3_TV, &plaintext_3_tv, &CRED_I_TV); assert_eq!(th_4, TH_4_TV); } @@ -1754,7 +1800,13 @@ mod tests { th_2_context_tv[..TH_2_TV.len()].copy_from_slice(&TH_2_TV[..]); const LEN_TV: usize = PLAINTEXT_2_LEN_TV; - let output = edhoc_kdf(&PRK_2E_TV, 0u8, &th_2_context_tv, SHA256_DIGEST_LEN, LEN_TV); + let output = default_crypto().edhoc_kdf( + &PRK_2E_TV, + 0u8, + &th_2_context_tv, + SHA256_DIGEST_LEN, + LEN_TV, + ); for i in 0..KEYSTREAM_2_TV.len() { assert_eq!(KEYSTREAM_2_TV[i], output[i]); } @@ -1763,7 +1815,7 @@ mod tests { context_info_mac_2[..CONTEXT_INFO_MAC_2_TV.len()] .copy_from_slice(&CONTEXT_INFO_MAC_2_TV[..]); - let output_2 = edhoc_kdf( + let output_2 = default_crypto().edhoc_kdf( &PRK_3E2M_TV, 2u8, &context_info_mac_2, @@ -1781,7 +1833,7 @@ mod tests { let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); let message_3_tv = BufferMessage3::from_hex(MESSAGE_3_TV); - let message_3 = encrypt_message_3(&PRK_3E2M_TV, &TH_3_TV, &plaintext_3_tv); + let message_3 = default_crypto().encrypt_message_3(&PRK_3E2M_TV, &TH_3_TV, &plaintext_3_tv); assert_eq!(message_3, message_3_tv); } @@ -1790,20 +1842,22 @@ mod tests { let plaintext_3_tv = BufferPlaintext3::from_hex(PLAINTEXT_3_TV); let message_3_tv = BufferMessage3::from_hex(MESSAGE_3_TV); - let plaintext_3 = decrypt_message_3(&PRK_3E2M_TV, &TH_3_TV, &message_3_tv); + let plaintext_3 = default_crypto().decrypt_message_3(&PRK_3E2M_TV, &TH_3_TV, &message_3_tv); assert!(plaintext_3.is_ok()); assert_eq!(plaintext_3.unwrap(), plaintext_3_tv); } #[test] fn test_compute_mac_3() { - let mac_3 = compute_mac_3(&PRK_4E3M_TV, &TH_3_TV, &ID_CRED_I_TV, &CRED_I_TV); + let mac_3 = + default_crypto().compute_mac_3(&PRK_4E3M_TV, &TH_3_TV, &ID_CRED_I_TV, &CRED_I_TV); assert_eq!(mac_3, MAC_3_TV); } #[test] fn test_compute_and_verify_mac_2() { - let rcvd_mac_2 = compute_mac_2(&PRK_3E2M_TV, &ID_CRED_R_TV, &CRED_R_TV, &TH_2_TV); + let rcvd_mac_2 = + default_crypto().compute_mac_2(&PRK_3E2M_TV, &ID_CRED_R_TV, &CRED_R_TV, &TH_2_TV); assert_eq!(rcvd_mac_2, MAC_2_TV); } @@ -1856,7 +1910,7 @@ mod tests { let ciphertext_2_tv = BufferPlaintext2::from_hex(CIPHERTEXT_2_TV); // test decryption let (plaintext_2, plaintext_2_len) = - encrypt_decrypt_ciphertext_2(&PRK_2E_TV, &TH_2_TV, &ciphertext_2_tv); + default_crypto().encrypt_decrypt_ciphertext_2(&PRK_2E_TV, &TH_2_TV, &ciphertext_2_tv); assert_eq!(plaintext_2_len, PLAINTEXT_2_LEN_TV); for i in 0..PLAINTEXT_2_LEN_TV { @@ -1869,7 +1923,7 @@ mod tests { // test encryption let (ciphertext_2, ciphertext_2_len) = - encrypt_decrypt_ciphertext_2(&PRK_2E_TV, &TH_2_TV, &plaintext_2_tmp); + default_crypto().encrypt_decrypt_ciphertext_2(&PRK_2E_TV, &TH_2_TV, &plaintext_2_tmp); assert_eq!(ciphertext_2_len, CIPHERTEXT_2_LEN_TV); for i in 0..CIPHERTEXT_2_LEN_TV { @@ -1879,19 +1933,19 @@ mod tests { #[test] fn test_compute_prk_4e3m() { - let prk_4e3m = compute_prk_4e3m(&SALT_4E3M_TV, &SK_I_TV, &G_Y_TV); + let prk_4e3m = default_crypto().compute_prk_4e3m(&SALT_4E3M_TV, &SK_I_TV, &G_Y_TV); assert_eq!(prk_4e3m, PRK_4E3M_TV); } #[test] fn test_compute_prk_3e2m() { - let prk_3e2m = compute_prk_3e2m(&SALT_3E2M_TV, &X_TV, &G_R_TV); + let prk_3e2m = default_crypto().compute_prk_3e2m(&SALT_3E2M_TV, &X_TV, &G_R_TV); assert_eq!(prk_3e2m, PRK_3E2M_TV); } #[test] fn test_compute_prk_2e() { - let prk_2e = compute_prk_2e(&X_TV, &G_Y_TV, &TH_2_TV); + let prk_2e = default_crypto().compute_prk_2e(&X_TV, &G_Y_TV, &TH_2_TV); assert_eq!(prk_2e, PRK_2E_TV); } @@ -2003,7 +2057,7 @@ mod tests { let mut th_4_context: BytesMaxContextBuffer = [0x00; MAX_KDF_CONTEXT_LEN]; th_4_context[..TH_4_TV.len()].copy_from_slice(&TH_4_TV[..]); - let prk_out_buf = edhoc_kdf( + let prk_out_buf = default_crypto().edhoc_kdf( &PRK_4E3M_TV, 7u8, &th_4_context, @@ -2018,7 +2072,7 @@ mod tests { #[test] fn test_compute_prk_exporter() { let mut prk_exporter: BytesHashLen = [0x00; SHA256_DIGEST_LEN]; - let prk_exporter_buf = edhoc_kdf( + let prk_exporter_buf = default_crypto().edhoc_kdf( &PRK_OUT_TV, 10u8, &[0x00; MAX_KDF_CONTEXT_LEN], @@ -2032,7 +2086,7 @@ mod tests { #[test] fn test_compute_oscore_master_secret_salt() { - let oscore_master_secret_buf = edhoc_kdf( + let oscore_master_secret_buf = default_crypto().edhoc_kdf( &PRK_EXPORTER_TV, 0u8, &[0x00; MAX_KDF_CONTEXT_LEN], @@ -2044,7 +2098,7 @@ mod tests { &OSCORE_MASTER_SECRET_TV[..] ); - let oscore_master_salt_buf = edhoc_kdf( + let oscore_master_salt_buf = default_crypto().edhoc_kdf( &PRK_EXPORTER_TV, 1u8, &[0x00; MAX_KDF_CONTEXT_LEN], diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 19cc1ead..70a29208 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,8 +1,9 @@ #![cfg_attr(not(test), no_std)] pub use { - edhoc_consts::State as EdhocState, edhoc_consts::*, edhoc_crypto::*, - EdhocInitiatorState as EdhocInitiator, EdhocResponderState as EdhocResponder, + edhoc_consts::State as EdhocState, edhoc_consts::*, edhoc_crypto::default_crypto, + edhoc_crypto::CryptoTrait, EdhocInitiatorState as EdhocInitiator, + EdhocResponderState as EdhocResponder, }; #[cfg(any(feature = "ead-none", feature = "ead-zeroconf"))] @@ -86,7 +87,7 @@ impl<'a> EdhocResponderState<'a> { self: &mut EdhocResponderState<'a>, message_1: &BufferMessage1, ) -> Result<(), EDHOCError> { - let state = r_process_message_1(self.state, message_1)?; + let state = r_process_message_1(self.state, &mut default_crypto(), message_1)?; self.state = state; Ok(()) @@ -96,10 +97,11 @@ impl<'a> EdhocResponderState<'a> { self: &mut EdhocResponderState<'a>, c_r: u8, ) -> Result { - let (y, g_y) = edhoc_crypto::p256_generate_key_pair(); + let (y, g_y) = default_crypto().p256_generate_key_pair(); match r_prepare_message_2( self.state, + &mut default_crypto(), &self .id_cred_r .try_into() @@ -124,6 +126,7 @@ impl<'a> EdhocResponderState<'a> { ) -> Result<[u8; SHA256_DIGEST_LEN], EDHOCError> { match r_process_message_3( self.state, + &mut default_crypto(), message_3, &self .id_cred_i @@ -149,7 +152,14 @@ impl<'a> EdhocResponderState<'a> { let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; context_buf[..context.len()].copy_from_slice(context); - match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { + match edhoc_exporter( + self.state, + &mut default_crypto(), + label, + &context_buf, + context.len(), + length, + ) { Ok((state, output)) => { self.state = state; Ok(output) @@ -165,7 +175,12 @@ impl<'a> EdhocResponderState<'a> { let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; context_buf[..context.len()].copy_from_slice(context); - match edhoc_key_update(self.state, &context_buf, context.len()) { + match edhoc_key_update( + self.state, + &mut default_crypto(), + &context_buf, + context.len(), + ) { Ok((state, prk_out_new)) => { self.state = state; Ok(prk_out_new) @@ -223,9 +238,9 @@ impl<'a> EdhocInitiatorState<'a> { self: &mut EdhocInitiatorState<'a>, c_i: u8, ) -> Result { - let (x, g_x) = edhoc_crypto::p256_generate_key_pair(); + let (x, g_x) = default_crypto().p256_generate_key_pair(); - match i_prepare_message_1(self.state, x, g_x, c_i) { + match i_prepare_message_1(self.state, &mut default_crypto(), x, g_x, c_i) { Ok((state, message_1)) => { self.state = state; Ok(message_1) @@ -240,6 +255,7 @@ impl<'a> EdhocInitiatorState<'a> { ) -> Result { match i_process_message_2( self.state, + &mut default_crypto(), message_2, &self .id_cred_r @@ -264,6 +280,7 @@ impl<'a> EdhocInitiatorState<'a> { ) -> Result<(BufferMessage3, [u8; SHA256_DIGEST_LEN]), EDHOCError> { match i_prepare_message_3( self.state, + &mut default_crypto(), &self .id_cred_i .try_into() @@ -287,7 +304,14 @@ impl<'a> EdhocInitiatorState<'a> { let mut context_buf: BytesMaxContextBuffer = [0x00u8; MAX_KDF_CONTEXT_LEN]; context_buf[..context.len()].copy_from_slice(context); - match edhoc_exporter(self.state, label, &context_buf, context.len(), length) { + match edhoc_exporter( + self.state, + &mut default_crypto(), + label, + &context_buf, + context.len(), + length, + ) { Ok((state, output)) => { self.state = state; Ok(output) @@ -303,7 +327,12 @@ impl<'a> EdhocInitiatorState<'a> { let mut context_buf = [0x00u8; MAX_KDF_CONTEXT_LEN]; context_buf[..context.len()].copy_from_slice(context); - match edhoc_key_update(self.state, &context_buf, context.len()) { + match edhoc_key_update( + self.state, + &mut default_crypto(), + &context_buf, + context.len(), + ) { Ok((state, prk_out_new)) => { self.state = state; Ok(prk_out_new) @@ -327,9 +356,9 @@ pub fn generate_connection_identifier_cbor() -> u8 { /// generates an identifier that can be serialized as a single CBOR integer, i.e. -24 <= x <= 23 pub fn generate_connection_identifier() -> i8 { - let mut conn_id = edhoc_crypto::get_random_byte() as i8; + let mut conn_id = default_crypto().get_random_byte() as i8; while conn_id < -24 || conn_id > 23 { - conn_id = edhoc_crypto::get_random_byte() as i8; + conn_id = default_crypto().get_random_byte() as i8; } conn_id }