mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-25 16:36:54 +02:00
Merge branch 'tetanus-aes-gmac-siv' into tetanus-arc_pool
This commit is contained in:
commit
68fc397d34
1 changed files with 76 additions and 92 deletions
|
@ -9,69 +9,95 @@ use crate::{cipher_ctx::CipherCtx, ZEROES};
|
||||||
pub struct AesGmacSiv {
|
pub struct AesGmacSiv {
|
||||||
tag: [u8; 16],
|
tag: [u8; 16],
|
||||||
tmp: [u8; 16],
|
tmp: [u8; 16],
|
||||||
k0: Vec<u8>,
|
ecb_enc: CipherCtx,
|
||||||
k1: Vec<u8>,
|
ecb_dec: CipherCtx,
|
||||||
ctr: Option<CipherCtx>,
|
ctr: CipherCtx,
|
||||||
gmac: Option<CipherCtx>,
|
gmac: CipherCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AesGmacSiv {
|
impl AesGmacSiv {
|
||||||
/// Create a new keyed instance of AES-GMAC-SIV
|
/// Create a new keyed instance of AES-GMAC-SIV
|
||||||
/// The key may be of size 16, 24, or 32 bytes (128, 192, or 256 bits). Any other size will panic.
|
/// The key may be of size 16, 24, or 32 bytes (128, 192, or 256 bits). Any other size will panic.
|
||||||
pub fn new(k0: &[u8], k1: &[u8]) -> Self {
|
pub fn new(k0: &[u8], k1: &[u8]) -> Self {
|
||||||
if k0.len() != 32 && k0.len() != 24 && k0.len() != 16 {
|
let gmac = CipherCtx::new().unwrap();
|
||||||
panic!("AES supports 128, 192, or 256 bits keys");
|
unsafe {
|
||||||
|
let t = match k0.len() {
|
||||||
|
16 => ffi::EVP_aes_128_gcm(),
|
||||||
|
24 => ffi::EVP_aes_192_gcm(),
|
||||||
|
32 => ffi::EVP_aes_256_gcm(),
|
||||||
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32"),
|
||||||
|
};
|
||||||
|
gmac.cipher_init::<true>(t, k0.as_ptr(), ptr::null_mut()).unwrap();
|
||||||
}
|
}
|
||||||
if k1.len() != k0.len() {
|
let ctr = CipherCtx::new().unwrap();
|
||||||
panic!("k0 and k1 must be of the same size");
|
unsafe {
|
||||||
|
let t = match k1.len() {
|
||||||
|
16 => ffi::EVP_aes_128_ctr(),
|
||||||
|
24 => ffi::EVP_aes_192_ctr(),
|
||||||
|
32 => ffi::EVP_aes_256_ctr(),
|
||||||
|
_ => panic!("Aes KEY_SIZE must be 16, 24 or 32"),
|
||||||
|
};
|
||||||
|
ctr.cipher_init::<true>(t, k1.as_ptr(), ptr::null_mut()).unwrap();
|
||||||
}
|
}
|
||||||
|
let ecb_enc = CipherCtx::new().unwrap();
|
||||||
|
unsafe {
|
||||||
|
let t = match 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"),
|
||||||
|
};
|
||||||
|
ecb_enc.cipher_init::<true>(t, k1.as_ptr(), ptr::null_mut()).unwrap();
|
||||||
|
ffi::EVP_CIPHER_CTX_set_padding(ecb_enc.as_ptr(), 0);
|
||||||
|
}
|
||||||
|
let ecb_dec = CipherCtx::new().unwrap();
|
||||||
|
unsafe {
|
||||||
|
let t = match 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"),
|
||||||
|
};
|
||||||
|
ecb_dec.cipher_init::<false>(t, k1.as_ptr(), ptr::null_mut()).unwrap();
|
||||||
|
ffi::EVP_CIPHER_CTX_set_padding(ecb_dec.as_ptr(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
AesGmacSiv {
|
AesGmacSiv {
|
||||||
tag: [0_u8; 16],
|
tag: [0_u8; 16],
|
||||||
tmp: [0_u8; 16],
|
tmp: [0_u8; 16],
|
||||||
k0: k0.to_vec(),
|
ecb_dec,
|
||||||
k1: k1.to_vec(),
|
ecb_enc,
|
||||||
ctr: None,
|
ctr,
|
||||||
gmac: None,
|
gmac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset to prepare for another encrypt or decrypt operation.
|
/// Reset to prepare for another encrypt or decrypt operation.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {}
|
||||||
let _ = self.ctr.take();
|
|
||||||
let _ = self.gmac.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize for encryption.
|
/// Initialize for encryption.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
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 ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k0.len() {
|
self.gmac
|
||||||
16 => ffi::EVP_aes_128_gcm(),
|
.cipher_init::<true>(ptr::null_mut(), ptr::null_mut(), self.tag[0..12].as_ptr())
|
||||||
24 => ffi::EVP_aes_192_gcm(),
|
.unwrap();
|
||||||
32 => ffi::EVP_aes_256_gcm(),
|
|
||||||
_ => 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).
|
||||||
/// This can currently only be called once. Multiple calls will result in corrupt data.
|
/// This can currently only be called once. Multiple calls will result in corrupt data.
|
||||||
#[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();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gmac.update::<true>(data, ptr::null_mut()).unwrap();
|
self.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;
|
||||||
gmac.update::<true>(&ZEROES[0..pad], ptr::null_mut()).unwrap();
|
self.gmac.update::<true>(&ZEROES[0..pad], ptr::null_mut()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,17 +107,16 @@ impl AesGmacSiv {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encrypt_first_pass(&mut self, plaintext: &[u8]) {
|
pub fn encrypt_first_pass(&mut self, plaintext: &[u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gmac.as_mut().unwrap().update::<true>(plaintext, ptr::null_mut()).unwrap();
|
self.gmac.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();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gmac.finalize::<true>(self.tmp.as_mut_ptr()).unwrap();
|
self.gmac.finalize::<true>(ptr::null_mut()).unwrap();
|
||||||
gmac.tag(&mut self.tmp).unwrap();
|
self.gmac.tag(&mut self.tmp).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tag[8] = self.tmp[0] ^ self.tmp[8];
|
self.tag[8] = self.tmp[0] ^ self.tmp[8];
|
||||||
|
@ -103,36 +128,19 @@ impl AesGmacSiv {
|
||||||
self.tag[14] = self.tmp[6] ^ self.tmp[14];
|
self.tag[14] = self.tmp[6] ^ self.tmp[14];
|
||||||
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; 16];
|
||||||
|
|
||||||
let ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k1.len() {
|
self.ecb_enc.update::<true>(&self.tag, tag_tmp.as_mut_ptr()).unwrap();
|
||||||
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);
|
||||||
self.tmp.copy_from_slice(&tag_tmp[0..16]);
|
self.tmp.copy_from_slice(&tag_tmp);
|
||||||
|
|
||||||
self.tmp[12] &= 0x7f;
|
self.tmp[12] &= 0x7f;
|
||||||
|
|
||||||
let ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k1.len() {
|
self.ctr.cipher_init::<true>(ptr::null_mut(), ptr::null_mut(), self.tmp.as_ptr()).unwrap();
|
||||||
16 => ffi::EVP_aes_128_ctr(),
|
|
||||||
24 => ffi::EVP_aes_192_ctr(),
|
|
||||||
32 => ffi::EVP_aes_256_ctr(),
|
|
||||||
_ => 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.
|
||||||
|
@ -140,7 +148,7 @@ impl AesGmacSiv {
|
||||||
#[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]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.ctr.as_mut().unwrap().update::<true>(plaintext, ciphertext.as_mut_ptr()).unwrap();
|
self.ctr.update::<true>(plaintext, ciphertext.as_mut_ptr()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +158,7 @@ impl AesGmacSiv {
|
||||||
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]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let out = plaintext_to_ciphertext.as_mut_ptr();
|
let out = plaintext_to_ciphertext.as_mut_ptr();
|
||||||
self.ctr.as_mut().unwrap().update::<true>(plaintext_to_ciphertext, out).unwrap();
|
self.ctr.update::<true>(plaintext_to_ciphertext, out).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,46 +176,23 @@ impl AesGmacSiv {
|
||||||
self.tmp.copy_from_slice(tag);
|
self.tmp.copy_from_slice(tag);
|
||||||
self.tmp[12] &= 0x7f;
|
self.tmp[12] &= 0x7f;
|
||||||
|
|
||||||
let ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k1.len() {
|
self.ctr
|
||||||
16 => ffi::EVP_aes_128_ctr(),
|
.cipher_init::<false>(ptr::null_mut(), ptr::null_mut(), self.tmp.as_ptr())
|
||||||
24 => ffi::EVP_aes_192_ctr(),
|
.unwrap();
|
||||||
32 => ffi::EVP_aes_256_ctr(),
|
|
||||||
_ => 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; 16];
|
||||||
|
|
||||||
let ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k1.len() {
|
self.ecb_dec.update::<false>(&tag, tag_tmp.as_mut_ptr()).unwrap();
|
||||||
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);
|
||||||
tag_tmp[8..12].fill(0);
|
tag_tmp[8..12].fill(0);
|
||||||
|
|
||||||
let ctx = CipherCtx::new().unwrap();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = match self.k0.len() {
|
self.gmac.cipher_init::<true>(ptr::null_mut(), ptr::null_mut(), tag_tmp.as_ptr()).unwrap();
|
||||||
16 => ffi::EVP_aes_128_gcm(),
|
|
||||||
24 => ffi::EVP_aes_192_gcm(),
|
|
||||||
32 => ffi::EVP_aes_256_gcm(),
|
|
||||||
_ => 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.
|
||||||
|
@ -221,8 +206,8 @@ impl AesGmacSiv {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) {
|
pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.ctr.as_mut().unwrap().update::<false>(ciphertext, plaintext.as_mut_ptr()).unwrap();
|
self.ctr.update::<false>(ciphertext, plaintext.as_mut_ptr()).unwrap();
|
||||||
self.gmac.as_mut().unwrap().update::<false>(plaintext, ptr::null_mut()).unwrap();
|
self.gmac.update::<true>(plaintext, ptr::null_mut()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,10 +225,9 @@ impl AesGmacSiv {
|
||||||
/// If this returns false the message should be dropped.
|
/// If this returns false the message should be dropped.
|
||||||
#[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();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gmac.finalize::<false>(self.tmp.as_mut_ptr()).unwrap();
|
self.gmac.finalize::<true>(self.tmp.as_mut_ptr()).unwrap();
|
||||||
gmac.tag(&mut self.tmp).unwrap();
|
self.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])
|
||||||
|
|
Loading…
Add table
Reference in a new issue