Initial Dosh implementation
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use chacha20poly1305::aead::{Aead, KeyInit, Payload};
|
||||
use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce};
|
||||
use hkdf::Hkdf;
|
||||
use hmac::{Hmac, Mac};
|
||||
use rand::RngCore;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
pub type HmacSha256 = Hmac<Sha256>;
|
||||
|
||||
pub fn random_32() -> [u8; 32] {
|
||||
let mut out = [0u8; 32];
|
||||
rand::thread_rng().fill_bytes(&mut out);
|
||||
out
|
||||
}
|
||||
|
||||
pub fn random_16() -> [u8; 16] {
|
||||
let mut out = [0u8; 16];
|
||||
rand::thread_rng().fill_bytes(&mut out);
|
||||
out
|
||||
}
|
||||
|
||||
pub fn random_12() -> [u8; 12] {
|
||||
let mut out = [0u8; 12];
|
||||
rand::thread_rng().fill_bytes(&mut out);
|
||||
out
|
||||
}
|
||||
|
||||
pub fn hmac_sha256(key: &[u8], parts: &[&[u8]]) -> [u8; 32] {
|
||||
let mut mac = <HmacSha256 as Mac>::new_from_slice(key).expect("HMAC accepts any key size");
|
||||
for part in parts {
|
||||
mac.update(part);
|
||||
}
|
||||
mac.finalize().into_bytes().into()
|
||||
}
|
||||
|
||||
pub fn verify_hmac(key: &[u8], parts: &[&[u8]], expected: &[u8; 32]) -> bool {
|
||||
let actual = hmac_sha256(key, parts);
|
||||
constant_time_eq(&actual, expected)
|
||||
}
|
||||
|
||||
pub fn sha256(data: &[u8]) -> [u8; 32] {
|
||||
Sha256::digest(data).into()
|
||||
}
|
||||
|
||||
pub fn hkdf32(secret: &[u8], salt: &[u8], info: &[u8]) -> Result<[u8; 32]> {
|
||||
let hk = Hkdf::<Sha256>::new(Some(salt), secret);
|
||||
let mut out = [0u8; 32];
|
||||
hk.expand(info, &mut out)
|
||||
.map_err(|_| anyhow!("HKDF expand failed"))?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn nonce_from(direction: u32, seq: u64) -> [u8; 12] {
|
||||
let mut nonce = [0u8; 12];
|
||||
nonce[..4].copy_from_slice(&direction.to_be_bytes());
|
||||
nonce[4..].copy_from_slice(&seq.to_be_bytes());
|
||||
nonce
|
||||
}
|
||||
|
||||
pub fn seal(key: &[u8; 32], nonce: &[u8; 12], aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>> {
|
||||
let cipher = ChaCha20Poly1305::new(Key::from_slice(key));
|
||||
cipher
|
||||
.encrypt(
|
||||
Nonce::from_slice(nonce),
|
||||
Payload {
|
||||
msg: plaintext,
|
||||
aad,
|
||||
},
|
||||
)
|
||||
.map_err(|_| anyhow!("encrypt failed"))
|
||||
}
|
||||
|
||||
pub fn open(key: &[u8; 32], nonce: &[u8; 12], aad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
|
||||
let cipher = ChaCha20Poly1305::new(Key::from_slice(key));
|
||||
cipher
|
||||
.decrypt(
|
||||
Nonce::from_slice(nonce),
|
||||
Payload {
|
||||
msg: ciphertext,
|
||||
aad,
|
||||
},
|
||||
)
|
||||
.map_err(|_| anyhow!("decrypt failed"))
|
||||
}
|
||||
|
||||
fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
|
||||
if a.len() != b.len() {
|
||||
return false;
|
||||
}
|
||||
let mut diff = 0u8;
|
||||
for (x, y) in a.iter().zip(b.iter()) {
|
||||
diff |= x ^ y;
|
||||
}
|
||||
diff == 0
|
||||
}
|
||||
Reference in New Issue
Block a user