mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-22 22:33:58 -07:00
added a port of aes_gmac_siv
This commit is contained in:
parent
e9ff9b98f1
commit
bac600ba2e
1 changed files with 111 additions and 63 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use foreign_types::ForeignType;
|
||||||
|
|
||||||
|
use crate::cipher_ctx::CipherCtx;
|
||||||
|
|
||||||
|
pub const ZEROES: [u8; 64] = [0_u8; 64];
|
||||||
|
|
||||||
/// AES-GMAC-SIV encryptor/decryptor.
|
/// AES-GMAC-SIV encryptor/decryptor.
|
||||||
pub struct AesGmacSiv {
|
pub struct AesGmacSiv {
|
||||||
|
@ -5,8 +12,8 @@ pub struct AesGmacSiv {
|
||||||
tmp: [u8; 16],
|
tmp: [u8; 16],
|
||||||
k0: Vec<u8>,
|
k0: Vec<u8>,
|
||||||
k1: Vec<u8>,
|
k1: Vec<u8>,
|
||||||
ctr: Option<Crypter>,
|
ctr: Option<CipherCtx>,
|
||||||
gmac: Option<Crypter>,
|
gmac: Option<CipherCtx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AesGmacSiv {
|
impl AesGmacSiv {
|
||||||
|
@ -41,15 +48,18 @@ impl AesGmacSiv {
|
||||||
pub fn encrypt_init(&mut self, iv: &[u8]) {
|
pub fn encrypt_init(&mut self, iv: &[u8]) {
|
||||||
self.tag[0..8].copy_from_slice(iv);
|
self.tag[0..8].copy_from_slice(iv);
|
||||||
self.tag[8..12].fill(0);
|
self.tag[8..12].fill(0);
|
||||||
let _ = self.gmac.replace(
|
|
||||||
Crypter::new(
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
aes_gcm_by_key_size(self.k0.len()),
|
unsafe {
|
||||||
Mode::Encrypt,
|
let t = match self.k0.len() {
|
||||||
self.k0.as_slice(),
|
16 => ffi::EVP_aes_128_gcm(),
|
||||||
Some(&self.tag[0..12]),
|
24 => ffi::EVP_aes_192_gcm(),
|
||||||
)
|
32 => ffi::EVP_aes_256_gcm(),
|
||||||
.unwrap(),
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
);
|
};
|
||||||
|
ctx.cipher_init::<true>(t, self.k0.as_mut_ptr(), self.tag[0..12].as_ptr()).unwrap();
|
||||||
|
}
|
||||||
|
let _ = self.gmac.replace(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set additional authenticated data (data to be authenticated but not encrypted).
|
/// Set additional authenticated data (data to be authenticated but not encrypted).
|
||||||
|
@ -57,11 +67,13 @@ impl AesGmacSiv {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_set_aad(&mut self, data: &[u8]) {
|
pub fn encrypt_set_aad(&mut self, data: &[u8]) {
|
||||||
let gmac = self.gmac.as_mut().unwrap();
|
let gmac = self.gmac.as_mut().unwrap();
|
||||||
let _ = gmac.aad_update(data);
|
unsafe {
|
||||||
|
gmac.update::<true>(data, ptr::null_mut()).unwrap();
|
||||||
let mut pad = data.len() & 0xf;
|
let mut pad = data.len() & 0xf;
|
||||||
if pad != 0 {
|
if pad != 0 {
|
||||||
pad = 16 - pad;
|
pad = 16 - pad;
|
||||||
let _ = gmac.aad_update(&crate::ZEROES[0..pad]);
|
gmac.update::<true>(&ZEROES[0..pad], ptr::null_mut()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,15 +81,20 @@ impl AesGmacSiv {
|
||||||
/// This may be called more than once.
|
/// This may be called more than once.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_first_pass(&mut self, plaintext: &[u8]) {
|
pub fn encrypt_first_pass(&mut self, plaintext: &[u8]) {
|
||||||
let _ = self.gmac.as_mut().unwrap().aad_update(plaintext);
|
unsafe {
|
||||||
|
self.gmac.as_mut().unwrap().update::<true>(plaintext, ptr::null_mut()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish first pass and begin second pass.
|
/// Finish first pass and begin second pass.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_first_pass_finish(&mut self) {
|
pub fn encrypt_first_pass_finish(&mut self) {
|
||||||
let gmac = self.gmac.as_mut().unwrap();
|
let gmac = self.gmac.as_mut().unwrap();
|
||||||
let _ = gmac.finalize(&mut self.tmp);
|
unsafe {
|
||||||
let _ = gmac.get_tag(&mut self.tmp);
|
gmac.finalize::<true>(self.tmp.as_mut_ptr()).unwrap();
|
||||||
|
gmac.tag(&mut self.tmp).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
self.tag[8] = self.tmp[0] ^ self.tmp[8];
|
self.tag[8] = self.tmp[0] ^ self.tmp[8];
|
||||||
self.tag[9] = self.tmp[1] ^ self.tmp[9];
|
self.tag[9] = self.tmp[1] ^ self.tmp[9];
|
||||||
self.tag[10] = self.tmp[2] ^ self.tmp[10];
|
self.tag[10] = self.tmp[2] ^ self.tmp[10];
|
||||||
|
@ -88,41 +105,54 @@ impl AesGmacSiv {
|
||||||
self.tag[15] = self.tmp[7] ^ self.tmp[15];
|
self.tag[15] = self.tmp[7] ^ self.tmp[15];
|
||||||
|
|
||||||
let mut tag_tmp = [0_u8; 32];
|
let mut tag_tmp = [0_u8; 32];
|
||||||
let mut ecb = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Encrypt, self.k1.as_slice(), None).unwrap();
|
|
||||||
ecb.pad(false);
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
if ecb.update(&self.tag, &mut tag_tmp).unwrap() != 16 {
|
unsafe {
|
||||||
assert_eq!(ecb.finalize(&mut tag_tmp).unwrap(), 16);
|
let t = match self.k1.len() {
|
||||||
|
16 => ffi::EVP_aes_128_ecb(),
|
||||||
|
24 => ffi::EVP_aes_192_ecb(),
|
||||||
|
32 => ffi::EVP_aes_256_ecb(),
|
||||||
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
|
};
|
||||||
|
ctx.cipher_init::<true>(t, self.k1.as_mut_ptr(), ptr::null_mut()).unwrap();
|
||||||
|
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
|
||||||
|
ctx.update::<true>(&self.tag, tag_tmp.as_mut_ptr()).unwrap();
|
||||||
}
|
}
|
||||||
self.tag.copy_from_slice(&tag_tmp[0..16]);
|
self.tag.copy_from_slice(&tag_tmp[0..16]);
|
||||||
self.tmp.copy_from_slice(&tag_tmp[0..16]);
|
self.tmp.copy_from_slice(&tag_tmp[0..16]);
|
||||||
|
|
||||||
self.tmp[12] &= 0x7f;
|
self.tmp[12] &= 0x7f;
|
||||||
let _ = self.ctr.replace(
|
|
||||||
Crypter::new(
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
aes_ctr_by_key_size(self.k1.len()),
|
unsafe {
|
||||||
Mode::Encrypt,
|
let t = match self.k1.len() {
|
||||||
self.k1.as_slice(),
|
16 => ffi::EVP_aes_128_ctr(),
|
||||||
Some(&self.tmp),
|
24 => ffi::EVP_aes_192_ctr(),
|
||||||
)
|
32 => ffi::EVP_aes_256_ctr(),
|
||||||
.unwrap(),
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
);
|
};
|
||||||
|
ctx.cipher_init::<true>(t, self.k1.as_mut_ptr(), self.tmp.as_ptr()).unwrap();
|
||||||
|
}
|
||||||
|
let _ = self.ctr.replace(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feed plaintext for second pass and write ciphertext to supplied buffer.
|
/// Feed plaintext for second pass and write ciphertext to supplied buffer.
|
||||||
/// This may be called more than once.
|
/// This may be called more than once.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_second_pass(&mut self, plaintext: &[u8], ciphertext: &mut [u8]) {
|
pub fn encrypt_second_pass(&mut self, plaintext: &[u8], ciphertext: &mut [u8]) {
|
||||||
let _ = self.ctr.as_mut().unwrap().update(plaintext, ciphertext);
|
unsafe {
|
||||||
|
self.ctr.as_mut().unwrap().update::<true>(plaintext, ciphertext.as_mut_ptr()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt plaintext in place.
|
/// Encrypt plaintext in place.
|
||||||
/// This may be called more than once.
|
/// This may be called more than once.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_second_pass_in_place(&mut self, plaintext_to_ciphertext: &mut [u8]) {
|
pub fn encrypt_second_pass_in_place(&mut self, plaintext_to_ciphertext: &mut [u8]) {
|
||||||
let _ = self.ctr.as_mut().unwrap().update(
|
unsafe {
|
||||||
unsafe { std::slice::from_raw_parts(plaintext_to_ciphertext.as_ptr(), plaintext_to_ciphertext.len()) },
|
let out = plaintext_to_ciphertext.as_mut_ptr();
|
||||||
plaintext_to_ciphertext,
|
self.ctr.as_mut().unwrap().update::<true>(plaintext_to_ciphertext, out).unwrap();
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish second pass and return a reference to the tag for this message.
|
/// Finish second pass and return a reference to the tag for this message.
|
||||||
|
@ -138,33 +168,47 @@ impl AesGmacSiv {
|
||||||
pub fn decrypt_init(&mut self, tag: &[u8]) {
|
pub fn decrypt_init(&mut self, tag: &[u8]) {
|
||||||
self.tmp.copy_from_slice(tag);
|
self.tmp.copy_from_slice(tag);
|
||||||
self.tmp[12] &= 0x7f;
|
self.tmp[12] &= 0x7f;
|
||||||
let _ = self.ctr.replace(
|
|
||||||
Crypter::new(
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
aes_ctr_by_key_size(self.k1.len()),
|
unsafe {
|
||||||
Mode::Decrypt,
|
let t = match self.k1.len() {
|
||||||
self.k1.as_slice(),
|
16 => ffi::EVP_aes_128_ctr(),
|
||||||
Some(&self.tmp),
|
24 => ffi::EVP_aes_192_ctr(),
|
||||||
)
|
32 => ffi::EVP_aes_256_ctr(),
|
||||||
.unwrap(),
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
);
|
};
|
||||||
|
ctx.cipher_init::<false>(t, self.k1.as_mut_ptr(), self.tmp.as_ptr()).unwrap();
|
||||||
|
}
|
||||||
|
let _ = self.ctr.replace(ctx);
|
||||||
|
|
||||||
let mut tag_tmp = [0_u8; 32];
|
let mut tag_tmp = [0_u8; 32];
|
||||||
let mut ecb = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Decrypt, self.k1.as_slice(), None).unwrap();
|
|
||||||
ecb.pad(false);
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
if ecb.update(tag, &mut tag_tmp).unwrap() != 16 {
|
unsafe {
|
||||||
assert_eq!(ecb.finalize(&mut tag_tmp).unwrap(), 16);
|
let t = match self.k1.len() {
|
||||||
|
16 => ffi::EVP_aes_128_ecb(),
|
||||||
|
24 => ffi::EVP_aes_192_ecb(),
|
||||||
|
32 => ffi::EVP_aes_256_ecb(),
|
||||||
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
|
};
|
||||||
|
ctx.cipher_init::<false>(t, self.k1.as_mut_ptr(), ptr::null_mut()).unwrap();
|
||||||
|
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
|
||||||
|
ctx.update::<false>(&self.tag, tag_tmp.as_mut_ptr()).unwrap();
|
||||||
}
|
}
|
||||||
self.tag.copy_from_slice(&tag_tmp[0..16]);
|
self.tag.copy_from_slice(&tag_tmp[0..16]);
|
||||||
tag_tmp[8..12].fill(0);
|
tag_tmp[8..12].fill(0);
|
||||||
let _ = self.gmac.replace(
|
|
||||||
Crypter::new(
|
let mut ctx = CipherCtx::new().unwrap();
|
||||||
aes_gcm_by_key_size(self.k0.len()),
|
unsafe {
|
||||||
Mode::Encrypt,
|
let t = match self.k0.len() {
|
||||||
self.k0.as_slice(),
|
16 => ffi::EVP_aes_128_gcm(),
|
||||||
Some(&tag_tmp[0..12]),
|
24 => ffi::EVP_aes_192_gcm(),
|
||||||
)
|
32 => ffi::EVP_aes_256_gcm(),
|
||||||
.unwrap(),
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32")
|
||||||
);
|
};
|
||||||
|
ctx.cipher_init::<true>(t, self.k0.as_mut_ptr(), self.tag[0..12].as_ptr()).unwrap();
|
||||||
|
}
|
||||||
|
let _ = self.gmac.replace(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set additional authenticated data to be checked.
|
/// Set additional authenticated data to be checked.
|
||||||
|
@ -177,8 +221,10 @@ impl AesGmacSiv {
|
||||||
/// This may be called more than once.
|
/// This may be called more than once.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) {
|
pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) {
|
||||||
let _ = self.ctr.as_mut().unwrap().update(ciphertext, plaintext);
|
unsafe {
|
||||||
let _ = self.gmac.as_mut().unwrap().aad_update(plaintext);
|
self.ctr.as_mut().unwrap().update::<false>(ciphertext, plaintext.as_mut_ptr()).unwrap();
|
||||||
|
self.gmac.as_mut().unwrap().update::<false>(plaintext, ptr::null_mut()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt ciphertext in place.
|
/// Decrypt ciphertext in place.
|
||||||
|
@ -196,8 +242,10 @@ impl AesGmacSiv {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn decrypt_finish(&mut self) -> Option<&[u8; 16]> {
|
pub fn decrypt_finish(&mut self) -> Option<&[u8; 16]> {
|
||||||
let gmac = self.gmac.as_mut().unwrap();
|
let gmac = self.gmac.as_mut().unwrap();
|
||||||
let _ = gmac.finalize(&mut self.tmp);
|
unsafe {
|
||||||
let _ = gmac.get_tag(&mut self.tmp);
|
gmac.finalize::<false>(self.tmp.as_mut_ptr()).unwrap();
|
||||||
|
gmac.tag(&mut self.tmp).unwrap();
|
||||||
|
}
|
||||||
if (self.tag[8] == self.tmp[0] ^ self.tmp[8])
|
if (self.tag[8] == self.tmp[0] ^ self.tmp[8])
|
||||||
&& (self.tag[9] == self.tmp[1] ^ self.tmp[9])
|
&& (self.tag[9] == self.tmp[1] ^ self.tmp[9])
|
||||||
&& (self.tag[10] == self.tmp[2] ^ self.tmp[10])
|
&& (self.tag[10] == self.tmp[2] ^ self.tmp[10])
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue