diff options
Diffstat (limited to 'src/crypto.rs')
-rw-r--r-- | src/crypto.rs | 99 |
1 files changed, 22 insertions, 77 deletions
diff --git a/src/crypto.rs b/src/crypto.rs index d681e86..2063c9b 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -36,39 +36,6 @@ fn xor<const N: usize>(l: &[u8; N], r: &[u8; N]) -> [u8; N] { result } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(try_from = "String", into = "String")] -pub struct SecretBytes<const N: usize>(pub [u8; N]); - -impl<const N: usize> Debug for SecretBytes<N> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - fmt.write_fmt(format_args!("SecretBytes {{ raw: {} }}", hex::encode(&self.0))) - } -} - -impl<const N: usize> From<SecretBytes<N>> for String { - fn from(sb: SecretBytes<N>) -> Self { - hex::encode(&sb.0) - } -} - -impl<const N: usize> TryFrom<String> for SecretBytes<N> { - type Error = hex::FromHexError; - - fn try_from(value: String) -> Result<Self, Self::Error> { - let mut result = Self([0; N]); - hex::decode_to_slice(value, &mut result.0)?; - Ok(result) - } -} - -impl From<SecretBytes<32>> for Output { - fn from(s: SecretBytes<32>) -> Output { - #[allow(clippy::unwrap_used)] - Output::new(&s.0).unwrap() - } -} - mod from_hkdf { use hkdf::Hkdf; use sha2::Sha256; @@ -78,7 +45,6 @@ mod from_hkdf { // and copies never fail mod private { pub trait Seal {} - impl<const N: usize> Seal for super::super::SecretBytes<N> {} impl<const N: usize> Seal for [u8; N] {} impl<L: Seal, R: Seal> Seal for (L, R) {} } @@ -88,14 +54,6 @@ mod from_hkdf { fn from_hkdf(bytes: &[u8]) -> Self; } - impl<const N: usize> FromHkdf for super::SecretBytes<N> { - const SIZE: usize = N; - fn from_hkdf(bytes: &[u8]) -> Self { - #[allow(clippy::unwrap_used)] - Self(bytes.try_into().unwrap()) - } - } - impl<const N: usize> FromHkdf for [u8; N] { const SIZE: usize = N; fn from_hkdf(bytes: &[u8]) -> Self { @@ -124,19 +82,8 @@ mod from_hkdf { use from_hkdf::from_hkdf; -impl<const N: usize> SecretBytes<N> { - pub fn generate() -> Self { - let mut result = Self([0; N]); - rand::rngs::OsRng.fill_bytes(&mut result.0); - result - } -} - #[derive(Debug, Deserialize, Serialize)] -#[serde(transparent)] -pub(crate) struct AuthPW { - pw: SecretBytes<32>, -} +pub(crate) struct AuthPW(#[serde(with = "as_hex")] [u8; 32]); pub(crate) struct StretchedPW { pw: Output, @@ -148,15 +95,16 @@ impl AuthPW { let mut buf = [0; Salt::MAX_LENGTH]; let params = scrypt::Params::new(16, 8, 1)?; let salt = salt.b64_decode(&mut buf)?; - scrypt(&self.pw.0, salt, ¶ms, &mut result)?; + scrypt(&self.0, salt, ¶ms, &mut result)?; Ok(StretchedPW { pw: Output::new(&result)? }) } } impl StretchedPW { pub fn verify_hash(&self) -> Output { - let raw: SecretBytes<32> = from_hkdf(self.pw.as_bytes(), &[NAMESPACE, b"verifyHash"]); - raw.into() + let raw: [u8; 32] = from_hkdf(self.pw.as_bytes(), &[NAMESPACE, b"verifyHash"]); + #[allow(clippy::unwrap_used)] + Output::new(&raw).unwrap() } fn wrap_wrap_key(&self) -> [u8; 32] { @@ -217,7 +165,7 @@ impl KeyFetchToken { pub(crate) struct KeyFetchReq { pub token_id: KeyFetchID, pub req_hmac_key: HawkKey, - key_request_key: SecretBytes<32>, + key_request_key: [u8; 32], } impl KeyFetchReq { @@ -233,21 +181,21 @@ impl KeyFetchReq { pub fn derive_resp(&self) -> KeyFetchResp { let (resp_hmac_key, resp_xor_key) = - from_hkdf(&self.key_request_key.0, &[NAMESPACE, b"account/keys"]); + from_hkdf(&self.key_request_key, &[NAMESPACE, b"account/keys"]); KeyFetchResp { resp_hmac_key, resp_xor_key } } } pub(crate) struct KeyFetchResp { - resp_hmac_key: SecretBytes<32>, - resp_xor_key: SecretBytes<64>, + resp_hmac_key: [u8; 32], + resp_xor_key: [u8; 64], } impl KeyFetchResp { pub fn wrap_keys(&self, keys: &KeyBundle) -> WrappedKeyBundle { - let ciphertext = xor(&self.resp_xor_key.0, &keys.to_bytes().0); + let ciphertext = xor(&self.resp_xor_key, &keys.to_bytes()); #[allow(clippy::unwrap_used)] - let mut hmac = Hmac::<Sha256>::new_from_slice(&self.resp_hmac_key.0).unwrap(); + let mut hmac = Hmac::<Sha256>::new_from_slice(&self.resp_hmac_key).unwrap(); hmac.update(&ciphertext); let hmac = *hmac.finalize().into_bytes().as_ref(); WrappedKeyBundle { ciphertext, hmac } @@ -260,10 +208,10 @@ pub(crate) struct KeyBundle { } impl KeyBundle { - pub fn to_bytes(&self) -> SecretBytes<64> { - let mut result = SecretBytes([0; 64]); - result.0[0..32].copy_from_slice(&self.ka.0); - result.0[32..].copy_from_slice(&self.wrap_kb.0); + pub fn to_bytes(&self) -> [u8; 64] { + let mut result = [0; 64]; + result[0..32].copy_from_slice(&self.ka.0); + result[32..].copy_from_slice(&self.wrap_kb.0); result } } @@ -355,7 +303,7 @@ mod test { types::SecretKey, }; - use super::{AuthPW, SecretBytes}; + use super::AuthPW; #[test] fn test_derive_session() { @@ -386,17 +334,17 @@ mod test { hex!("87b8937f61d38d0e 29cd2d5600b3f4da 0aa48ac41de36a0e fe84bb4a9872ceb7") ); assert_eq!( - key_fetch.key_request_key.0, + key_fetch.key_request_key, hex!("14f338a9e8c6324d 9e102d4e6ee83b20 9796d5c74bb734a4 10e729e014a4a546") ); let resp = key_fetch.derive_resp(); assert_eq!( - resp.resp_hmac_key.0, + resp.resp_hmac_key, hex!("f824d2953aab9faf 51a1cb65ba9e7f9e 5bf91c8d8fd1ac1c 8c2d31853a8a1210") ); assert_eq!( - resp.resp_xor_key.0, + resp.resp_xor_key, hex!( "ce7d7aa77859b235 9932970bbe2101f2 e80d01faf9191bd5 ee52181d2f0b7809 8281ba8cff392543 3a89f7c3095e0c89 900a469d60790c83 3281c4df1a11c763" @@ -412,7 +360,7 @@ mod test { )), }; assert_eq!( - bundle.to_bytes().0, + bundle.to_bytes(), hex!( "2021222324252627 28292a2b2c2d2e2f 3031323334353637 38393a3b3c3d3e3f 7effe354abecbcb2 34a8dfc2d7644b4a d339b525589738f2 d27341bb8622ecd8" @@ -443,11 +391,8 @@ mod test { #[test] fn test_stretch() -> anyhow::Result<()> { - let auth_pw = AuthPW { - pw: SecretBytes(hex!( - "247b675ffb4c4631 0bc87e26d712153a be5e1c90ef00a478 4594f97ef54f2375" - )), - }; + let auth_pw = + AuthPW(hex!("247b675ffb4c4631 0bc87e26d712153a be5e1c90ef00a478 4594f97ef54f2375")); let stretched = auth_pw.stretch( SaltString::b64_encode(&hex!( |