From 7a7703a268476b4fa46bf2185c4f2de6dbf374bd Mon Sep 17 00:00:00 2001 From: mamoniot Date: Tue, 14 Mar 2023 17:45:48 -0400 Subject: [PATCH] switched to sha512 everywhere --- crypto/src/hash.rs | 6 +- zssp/src/proto.rs | 13 ++--- zssp/src/zssp.rs | 139 ++++++++++++++++++++++++++------------------- 3 files changed, 88 insertions(+), 70 deletions(-) diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index e71472b9c..808567fcf 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -276,12 +276,10 @@ pub fn hmac_sha512_into(key: &[u8], msg: &[u8], md: &mut [u8]) { hm.finish_into(md); } -pub fn hmac_sha512_secret(key: &[u8], msg: &[u8]) -> Secret { - debug_assert!(C <= HMAC_SHA512_SIZE); +pub fn hmac_sha512_secret(key: &[u8], msg: &[u8]) -> Secret { let mut hm = HMACSHA512::new(key); hm.update(msg); - let buff = hm.finish(); - unsafe { Secret::from_bytes(&buff[..C]) } + Secret::move_bytes(hm.finish()) } #[inline(always)] diff --git a/zssp/src/proto.rs b/zssp/src/proto.rs index 7952c9d30..b3d6a93dd 100644 --- a/zssp/src/proto.rs +++ b/zssp/src/proto.rs @@ -9,7 +9,7 @@ use std::mem::size_of; use pqc_kyber::{KYBER_CIPHERTEXTBYTES, KYBER_PUBLICKEYBYTES}; -use zerotier_crypto::hash::SHA384_HASH_SIZE; +use zerotier_crypto::hash::SHA512_HASH_SIZE; use zerotier_crypto::p384::P384_PUBLIC_KEY_SIZE; use crate::error::Error; @@ -26,9 +26,8 @@ pub const MAX_INIT_PAYLOAD_SIZE: usize = MAX_NOISE_HANDSHAKE_SIZE - ALICE_NOISE_ /// Initial value of 'h' /// echo -n 'Noise_XKpsk3_P384_AESGCM_SHA384_hybridKyber1024' | shasum -a 384 -pub(crate) const INITIAL_H: [u8; SHA384_HASH_SIZE] = [ - 0x35, 0x27, 0x16, 0x62, 0x58, 0x04, 0x0c, 0x7a, 0x99, 0xa8, 0x0b, 0x49, 0xb2, 0x6b, 0x25, 0xfb, 0xf5, 0x26, 0x2a, 0x26, 0xe7, 0xb3, 0x70, 0xcb, - 0x2c, 0x3c, 0xcb, 0x7f, 0xca, 0x20, 0x06, 0x91, 0x20, 0x55, 0x52, 0x8e, 0xd4, 0x3c, 0x97, 0xc3, 0xd5, 0x6c, 0xb4, 0x13, 0x02, 0x54, 0x83, 0x12, +pub(crate) const INITIAL_H: [u8; SHA512_HASH_SIZE] = [ + 0xd3, 0x18, 0x1c, 0xee, 0x05, 0x8d, 0x35, 0x06, 0x22, 0xcd, 0xfc, 0x46, 0x82, 0x2a, 0x60, 0x81, 0xf5, 0xe0, 0x47, 0x65, 0x57, 0x66, 0x53, 0x17, 0x95, 0xae, 0x33, 0x3c, 0x90, 0x83, 0x3b, 0xbf, 0x7f, 0x5e, 0xd7, 0x3d, 0x03, 0x39, 0x10, 0x03, 0x29, 0xfd, 0x2d, 0x59, 0xa0, 0x99, 0x56, 0x63, 0x18, 0x2d, 0x63, 0xb7, 0x8d, 0xd1, 0x7a, 0x2c, 0xf7, 0x92, 0x16, 0xdd, 0xfa, 0xf1, 0x05, 0x37, ]; /// Version 0: Noise_XK with NIST P-384 plus Kyber1024 hybrid exchange on session init. @@ -65,7 +64,7 @@ pub(crate) const MAX_NOISE_HANDSHAKE_FRAGMENTS: usize = 16; // enough room for p pub(crate) const MAX_NOISE_HANDSHAKE_SIZE: usize = MAX_NOISE_HANDSHAKE_FRAGMENTS * MIN_TRANSPORT_MTU; /// Size of keys used during derivation, mixing, etc. process. -pub(crate) const BASE_KEY_SIZE: usize = 64; +pub(crate) const NOISE_HASHLEN: usize = SHA512_HASH_SIZE; pub(crate) const AES_256_KEY_SIZE: usize = 32; pub(crate) const AES_HEADER_PROTECTION_KEY_SIZE: usize = 16; @@ -160,14 +159,14 @@ pub(crate) struct RekeyAck { pub session_protocol_version: u8, // -- start AES-GCM encrypted portion (using current key) pub bob_e: [u8; P384_PUBLIC_KEY_SIZE], - pub next_key_fingerprint: [u8; SHA384_HASH_SIZE], // SHA384(next secret) + pub next_key_fingerprint: [u8; SHA512_HASH_SIZE], // SHA384(next secret) // -- end AES-GCM encrypted portion pub gcm_tag: [u8; AES_GCM_TAG_SIZE], } impl RekeyAck { pub const ENC_START: usize = HEADER_SIZE + 1; - pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE + SHA384_HASH_SIZE; + pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE + SHA512_HASH_SIZE; pub const SIZE: usize = Self::AUTH_START + AES_GCM_TAG_SIZE; } diff --git a/zssp/src/zssp.rs b/zssp/src/zssp.rs index dd85ac1d1..c33d45f6e 100644 --- a/zssp/src/zssp.rs +++ b/zssp/src/zssp.rs @@ -15,8 +15,8 @@ use std::sync::atomic::{AtomicI64, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, MutexGuard, RwLock, Weak}; use zerotier_crypto::aes::{Aes, AesGcm}; -use zerotier_crypto::hash::{hmac_sha512_secret, SHA384, SHA384_HASH_SIZE}; -use zerotier_crypto::p384::{P384KeyPair, P384PublicKey, P384_ECDH_SHARED_SECRET_SIZE}; +use zerotier_crypto::hash::{SHA512, hmac_sha512_secret}; +use zerotier_crypto::p384::{P384KeyPair, P384PublicKey}; use zerotier_crypto::secret::Secret; use zerotier_crypto::{random, secure_eq}; @@ -106,8 +106,8 @@ struct IncomingIncompleteSession { timestamp: i64, alice_session_id: SessionId, bob_session_id: SessionId, - noise_h: [u8; SHA384_HASH_SIZE], - noise_es_ee: Secret, + noise_h: [u8; NOISE_HASHLEN], + noise_ck_es_ee: Secret, hk: Secret, header_protection_key: Secret, bob_noise_e_secret: P384KeyPair, @@ -116,9 +116,9 @@ struct IncomingIncompleteSession { struct OutgoingSessionOffer { last_retry_time: AtomicI64, - psk: Secret, - noise_h: [u8; SHA384_HASH_SIZE], - noise_es: Secret, + psk: Secret, + noise_h: [u8; NOISE_HASHLEN], + noise_ck_es: Secret, alice_noise_e_secret: P384KeyPair, alice_hk_secret: Secret, metadata: Option>, @@ -139,7 +139,7 @@ enum Offer { } struct SessionKey { - ratchet_key: Secret, // Key used in derivation of the next session key + ratchet_key: Secret, // Key used in derivation of the next session key receive_cipher_pool: [Mutex>; GCM_CIPHER_POOL_SIZE], // Pool of reusable sending ciphers send_cipher_pool: [Mutex>; GCM_CIPHER_POOL_SIZE], // Pool of reusable receiving ciphers rekey_at_time: i64, // Rekey at or after this time (ticks) @@ -290,7 +290,7 @@ impl Context { mtu: usize, remote_s_public_blob: &[u8], remote_s_public_p384: P384PublicKey, - psk: Secret, + psk: Secret, metadata: Option>, application_data: Application::Data, current_time: i64, @@ -302,9 +302,14 @@ impl Context { let alice_noise_e_secret = P384KeyPair::generate(); let alice_noise_e = alice_noise_e_secret.public_key_bytes().clone(); let noise_es = alice_noise_e_secret.agree(&remote_s_public_p384).ok_or(Error::InvalidParameter)?; + let noise_h = mix_hash(&mix_hash(&INITIAL_H, remote_s_public_blob), &alice_noise_e); + let noise_ck_es = hmac_sha512_secret(&INITIAL_H, noise_es.as_bytes()); let alice_hk_secret = pqc_kyber::keypair(&mut random::SecureRandom::default()); let header_protection_key: Secret = Secret(random::get_bytes_secure()); + // Init aesgcm before we move noise_ck_es + let mut gcm = AesGcm::new(&kbkdf256::(&noise_ck_es)); + let (local_session_id, session) = { let mut sessions = self.sessions.write().unwrap(); @@ -331,8 +336,8 @@ impl Context { outgoing_offer: Offer::NoiseXKInit(Box::new(OutgoingSessionOffer { last_retry_time: AtomicI64::new(current_time), psk, - noise_h: mix_hash(&mix_hash(&INITIAL_H, remote_s_public_blob), &alice_noise_e), - noise_es: noise_es.clone(), + noise_h, + noise_ck_es, alice_noise_e_secret, alice_hk_secret: Secret(alice_hk_secret.secret), metadata, @@ -367,7 +372,6 @@ impl Context { } // Encrypt and add authentication tag. - let mut gcm = AesGcm::new(&kbkdf::(noise_es.as_bytes())); gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_ALICE_NOISE_XK_INIT, 1)); gcm.aad(&offer.noise_h); gcm.crypt_in_place(&mut init_packet[AliceNoiseXKInit::ENC_START..AliceNoiseXKInit::AUTH_START]); @@ -736,9 +740,11 @@ impl Context { let noise_h = mix_hash(&mix_hash(&INITIAL_H, app.get_local_s_public_blob()), alice_noise_e.as_bytes()); let noise_h_next = mix_hash(&noise_h, &pkt_assembled[HEADER_SIZE..]); + let noise_ck_es = hmac_sha512_secret(&INITIAL_H, noise_es.as_bytes()); + drop(noise_es); // Decrypt and authenticate init packet, also proving that caller knows our static identity. - let mut gcm = AesGcm::new(&kbkdf::(noise_es.as_bytes())); + let mut gcm = AesGcm::new(&kbkdf256::(&noise_ck_es)); gcm.reset_init_gcm(&incoming_message_nonce); gcm.aad(&noise_h); gcm.crypt_in_place(&mut pkt_assembled[AliceNoiseXKInit::ENC_START..AliceNoiseXKInit::AUTH_START]); @@ -755,12 +761,12 @@ impl Context { let alice_session_id = SessionId::new_from_array(&pkt.alice_session_id).ok_or(Error::InvalidPacket)?; let header_protection_key = Secret(pkt.header_protection_key); - // Create Bob's ephemeral keys and derive noise_es_ee by agreeing with Alice's. Also create + // Create Bob's ephemeral keys and derive noise_ck by agreeing with Alice's. Also create // a Kyber ciphertext to send back to Alice. let bob_noise_e_secret = P384KeyPair::generate(); let bob_noise_e = bob_noise_e_secret.public_key_bytes().clone(); - let noise_es_ee = hmac_sha512_secret( - noise_es.as_bytes(), + let noise_ck_es_ee = hmac_sha512_secret( + noise_ck_es.as_bytes(), bob_noise_e_secret.agree(&alice_noise_e).ok_or(Error::FailedAuthentication)?.as_bytes(), ); let (bob_hk_ciphertext, hk) = pqc_kyber::encapsulate(&pkt.alice_hk_public, &mut random::SecureRandom::default()) @@ -787,7 +793,7 @@ impl Context { ack.bob_hk_ciphertext = bob_hk_ciphertext; // Encrypt main section of reply and attach tag. - let mut gcm = AesGcm::new(&kbkdf::(noise_es_ee.as_bytes())); + let mut gcm = AesGcm::new(&kbkdf256::(&noise_ck_es_ee)); gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_BOB_NOISE_XK_ACK, 1)); gcm.aad(&noise_h_next); gcm.crypt_in_place(&mut ack_packet[BobNoiseXKAck::ENC_START..BobNoiseXKAck::AUTH_START]); @@ -820,7 +826,7 @@ impl Context { alice_session_id, bob_session_id, noise_h: mix_hash(&mix_hash(&noise_h_next, &bob_noise_e), &ack_packet[HEADER_SIZE..]), - noise_es_ee: noise_es_ee.clone(), + noise_ck_es_ee, hk, bob_noise_e_secret, header_protection_key: Secret(pkt.header_protection_key), @@ -875,8 +881,8 @@ impl Context { // Derive noise_es_ee from Bob's ephemeral public key. let bob_noise_e = P384PublicKey::from_bytes(&pkt.bob_noise_e).ok_or(Error::FailedAuthentication)?; - let noise_es_ee = hmac_sha512_secret::( - outgoing_offer.noise_es.as_bytes(), + let noise_ck_es_ee = hmac_sha512_secret( + outgoing_offer.noise_ck_es.as_bytes(), outgoing_offer .alice_noise_e_secret .agree(&bob_noise_e) @@ -888,7 +894,7 @@ impl Context { let noise_h_next = mix_hash(&mix_hash(&outgoing_offer.noise_h, bob_noise_e.as_bytes()), &pkt_assembled[HEADER_SIZE..]); // Decrypt and authenticate Bob's reply. - let mut gcm = AesGcm::new(&kbkdf::(noise_es_ee.as_bytes())); + let mut gcm = AesGcm::new(&kbkdf256::(&noise_ck_es_ee)); gcm.reset_init_gcm(&incoming_message_nonce); gcm.aad(&outgoing_offer.noise_h); gcm.crypt_in_place(&mut pkt_assembled[BobNoiseXKAck::ENC_START..BobNoiseXKAck::AUTH_START]); @@ -910,9 +916,9 @@ impl Context { // Packet fully authenticated if session.update_receive_window(incoming_counter) { - let noise_es_ee_se_hk_psk = hmac_sha512_secret::( - hmac_sha512_secret::(noise_es_ee.as_bytes(), noise_se.as_bytes()).as_bytes(), - hmac_sha512_secret::(outgoing_offer.psk.as_bytes(), hk.as_bytes()).as_bytes(), + let noise_ck_es_ee_se_hk_psk = hmac_sha512_secret( + hmac_sha512_secret(noise_ck_es_ee.as_bytes(), noise_se.as_bytes()).as_bytes(), + hmac_sha512_secret(outgoing_offer.psk.as_bytes(), hk.as_bytes()).as_bytes(), ); let reply_message_nonce = create_message_nonce(PACKET_TYPE_ALICE_NOISE_XK_ACK, 2); @@ -929,8 +935,8 @@ impl Context { let mut enc_start = ack_len; ack_len = append_to_slice(&mut ack, ack_len, alice_s_public_blob)?; - let mut gcm = AesGcm::new(&kbkdf::( - hmac_sha512_secret::(noise_es_ee.as_bytes(), hk.as_bytes()).as_bytes(), + let mut gcm = AesGcm::new(&kbkdf256::( + &hmac_sha512_secret(noise_ck_es_ee.as_bytes(), hk.as_bytes()), )); gcm.reset_init_gcm(&reply_message_nonce); gcm.aad(&noise_h_next); @@ -947,8 +953,8 @@ impl Context { enc_start = ack_len; ack_len = append_to_slice(&mut ack, ack_len, metadata)?; - let mut gcm = AesGcm::new(&kbkdf::( - noise_es_ee_se_hk_psk.as_bytes(), + let mut gcm = AesGcm::new(&kbkdf256::( + &noise_ck_es_ee_se_hk_psk, )); gcm.reset_init_gcm(&reply_message_nonce); gcm.aad(&noise_h_next); @@ -962,7 +968,7 @@ impl Context { let mut state = session.state.write().unwrap(); let _ = state.remote_session_id.insert(bob_session_id); let _ = state.keys[0].insert(SessionKey::new::( - noise_es_ee_se_hk_psk, + noise_ck_es_ee_se_hk_psk, 1, current_time, 2, @@ -1035,8 +1041,8 @@ impl Context { let alice_static_public_blob = r.read_decrypt_auth( alice_static_public_blob_size, - kbkdf::( - hmac_sha512_secret::(incoming.noise_es_ee.as_bytes(), incoming.hk.as_bytes()).as_bytes(), + kbkdf256::( + &hmac_sha512_secret(incoming.noise_ck_es_ee.as_bytes(), incoming.hk.as_bytes()), ), &incoming.noise_h, &incoming_message_nonce, @@ -1053,9 +1059,9 @@ impl Context { let noise_h_next = mix_hash(&noise_h_next, psk.as_bytes()); // Complete Noise_XKpsk3 on Bob's side. - let noise_es_ee_se_hk_psk = hmac_sha512_secret::( - hmac_sha512_secret::( - incoming.noise_es_ee.as_bytes(), + let noise_ck_es_ee_se_hk_psk = hmac_sha512_secret( + hmac_sha512_secret( + incoming.noise_ck_es_ee.as_bytes(), incoming .bob_noise_e_secret .agree(&alice_noise_s) @@ -1063,7 +1069,7 @@ impl Context { .as_bytes(), ) .as_bytes(), - hmac_sha512_secret::(psk.as_bytes(), incoming.hk.as_bytes()).as_bytes(), + hmac_sha512_secret(psk.as_bytes(), incoming.hk.as_bytes()).as_bytes(), ); // Decrypt meta-data and verify the final key in the process. Copy meta-data @@ -1071,7 +1077,7 @@ impl Context { let alice_meta_data_size = r.read_u16()? as usize; let alice_meta_data = r.read_decrypt_auth( alice_meta_data_size, - kbkdf::(noise_es_ee_se_hk_psk.as_bytes()), + kbkdf256::(&noise_ck_es_ee_se_hk_psk), &noise_h_next, &incoming_message_nonce, )?; @@ -1091,7 +1097,7 @@ impl Context { physical_mtu: self.default_physical_mtu.load(Ordering::Relaxed), remote_session_id: Some(incoming.alice_session_id), keys: [ - Some(SessionKey::new::(noise_es_ee_se_hk_psk, 1, current_time, 2, true, true)), + Some(SessionKey::new::(noise_ck_es_ee_se_hk_psk, 1, current_time, 2, true, true)), None, ], current_key: 0, @@ -1151,9 +1157,9 @@ impl Context { let noise_es = app.get_local_s_keypair().agree(&alice_e).ok_or(Error::FailedAuthentication)?; let noise_ee = bob_e_secret.agree(&alice_e).ok_or(Error::FailedAuthentication)?; let noise_se = bob_e_secret.agree(&session.static_public_key).ok_or(Error::FailedAuthentication)?; - let noise_psk_se_ee_es = hmac_sha512_secret::( - hmac_sha512_secret::( - hmac_sha512_secret::(key.ratchet_key.as_bytes(), noise_es.as_bytes()).as_bytes(), + let noise_psk_se_ee_es = hmac_sha512_secret( + hmac_sha512_secret( + hmac_sha512_secret(key.ratchet_key.as_bytes(), noise_es.as_bytes()).as_bytes(), noise_ee.as_bytes(), ) .as_bytes(), @@ -1166,7 +1172,7 @@ impl Context { let reply: &mut RekeyAck = byte_array_as_proto_buffer_mut(&mut reply_buf).unwrap(); reply.session_protocol_version = SESSION_PROTOCOL_VERSION; reply.bob_e = *bob_e_secret.public_key_bytes(); - reply.next_key_fingerprint = SHA384::hash(noise_psk_se_ee_es.as_bytes()); + reply.next_key_fingerprint = SHA512::hash(noise_psk_se_ee_es.as_bytes()); let counter = session.get_next_outgoing_counter().ok_or(Error::MaxKeyLifetimeExceeded)?.get(); set_packet_header( @@ -1249,9 +1255,9 @@ impl Context { let noise_es = alice_e_secret.agree(&session.static_public_key).ok_or(Error::FailedAuthentication)?; let noise_ee = alice_e_secret.agree(&bob_e).ok_or(Error::FailedAuthentication)?; let noise_se = app.get_local_s_keypair().agree(&bob_e).ok_or(Error::FailedAuthentication)?; - let noise_psk_se_ee_es = hmac_sha512_secret::( - hmac_sha512_secret::( - hmac_sha512_secret::(key.ratchet_key.as_bytes(), noise_es.as_bytes()).as_bytes(), + let noise_psk_se_ee_es = hmac_sha512_secret( + hmac_sha512_secret( + hmac_sha512_secret(key.ratchet_key.as_bytes(), noise_es.as_bytes()).as_bytes(), noise_ee.as_bytes(), ) .as_bytes(), @@ -1260,7 +1266,7 @@ impl Context { // We need to check that the key Bob is acknowledging matches the latest sent offer. // Because of OOO, it might not, in which case this rekey must be cancelled and retried. - if secure_eq(&pkt.next_key_fingerprint, &SHA384::hash(noise_psk_se_ee_es.as_bytes())) { + if secure_eq(&pkt.next_key_fingerprint, &SHA512::hash(noise_psk_se_ee_es.as_bytes())) { if session.update_receive_window(incoming_counter) { // The new "Alice" knows Bob has the key since this is an ACK, so she can go // ahead and set current_key to the new key. Then when she sends something @@ -1391,10 +1397,10 @@ impl Session { } /// Get the ratchet count and a hash fingerprint of the current active key. - pub fn key_info(&self) -> Option<(u64, [u8; 48])> { + pub fn key_info(&self) -> Option<(u64, [u8; NOISE_HASHLEN])> { let state = self.state.read().unwrap(); if let Some(key) = state.keys[state.current_key].as_ref() { - Some((key.ratchet_count, SHA384::hash(key.ratchet_key.as_bytes()))) + Some((key.ratchet_count, SHA512::hash(key.ratchet_key.as_bytes()))) } else { None } @@ -1583,15 +1589,15 @@ fn assemble_fragments_into(fragments: &[A::IncomingPacketBu impl SessionKey { fn new( - key: Secret, + key: Secret, ratchet_count: u64, current_time: i64, current_counter: u64, bob: bool, confirmed: bool, ) -> Self { - let a2b = kbkdf::(key.as_bytes()); - let b2a = kbkdf::(key.as_bytes()); + let a2b = kbkdf256::(&key); + let b2a = kbkdf256::(&key); let (receive_key, send_key) = if bob { (a2b, b2a) } else { @@ -1600,7 +1606,7 @@ impl SessionKey { let receive_cipher_pool = std::array::from_fn(|_| Mutex::new(AesGcm::new(&receive_key))); let send_cipher_pool = std::array::from_fn(|_| Mutex::new(AesGcm::new(&send_key))); Self { - ratchet_key: kbkdf::(key.as_bytes()), + ratchet_key: kbkdf512::(&key), receive_cipher_pool, send_cipher_pool, rekey_at_time: current_time @@ -1680,8 +1686,8 @@ fn append_to_slice(s: &mut [u8], p: usize, d: &[u8]) -> Result { } /// MixHash to update 'h' during negotiation. -fn mix_hash(h: &[u8; SHA384_HASH_SIZE], m: &[u8]) -> [u8; SHA384_HASH_SIZE] { - let mut hasher = SHA384::new(); +fn mix_hash(h: &[u8; NOISE_HASHLEN], m: &[u8]) -> [u8; NOISE_HASHLEN] { + let mut hasher = SHA512::new(); hasher.update(h); hasher.update(m); hasher.finish() @@ -1689,11 +1695,11 @@ fn mix_hash(h: &[u8; SHA384_HASH_SIZE], m: &[u8]) -> [u8; SHA384_HASH_SIZE] { /// HMAC-SHA512 key derivation based on: https://csrc.nist.gov/publications/detail/sp/800-108/final (page 7) /// Cryptographically this isn't meaningfully different from HMAC(key, [label]) but this is how NIST rolls. -fn kbkdf(key: &[u8]) -> Secret { - //These are the values we have assigned to the 5 variables involved in https://csrc.nist.gov/publications/detail/sp/800-108/final: - // K_in = key, i = 0x01, Label = 'Z'||'T'||LABEL, Context = 0x00, L = (OUTPUT_BYTES * 8) +/// These are the values we have assigned to the 5 variables involved in https://csrc.nist.gov/publications/detail/sp/800-108/final: +/// K_in = key, i = 0x01, Label = 'Z'||'T'||LABEL, Context = 0x00, L = 512 or 256 as a u16 +fn kbkdf512(key: &Secret) -> Secret { hmac_sha512_secret( - key, + key.as_bytes(), &[ 1, b'Z', @@ -1701,11 +1707,26 @@ fn kbkdf(key: &[u8]) -> Secret> 8) & 0xff) as u8, - ((OUTPUT_BYTES * 8) & 0xff) as u8, + 2u8, + 0u8, ], ) } +fn kbkdf256(key: &Secret) -> Secret<32> { + hmac_sha512_secret( + key.as_bytes(), + &[ + 1, + b'Z', + b'T', + LABEL, + 0x00, + 0, + 1u8, + 0u8, + ], + ).first_n_clone() +} fn prng32(mut x: u32) -> u32 { // based on lowbias32 from https://nullprogram.com/blog/2018/07/31/