Fix openssl version of AES-GMAC-SIV, a few other things.

This commit is contained in:
Adam Ierymenko 2022-06-14 17:31:29 -04:00
parent 90e4199b90
commit 6940b97a92
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
6 changed files with 1169 additions and 77 deletions

View file

@ -70,7 +70,6 @@ impl AesCtr {
} }
/// AES-GMAC-SIV encryptor/decryptor. /// AES-GMAC-SIV encryptor/decryptor.
#[repr(align(8))] // allow tag and tmp to be accessed as u64 arrays as well
pub struct AesGmacSiv { pub struct AesGmacSiv {
tag: [u8; 16], tag: [u8; 16],
tmp: [u8; 16], tmp: [u8; 16],
@ -149,10 +148,16 @@ impl AesGmacSiv {
self.tag[13] = self.tmp[5] ^ self.tmp[13]; self.tag[13] = self.tmp[5] ^ self.tmp[13];
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; 32];
let _ = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Encrypt, self.k1.as_slice(), None).unwrap().update(&self.tag, &mut tag_tmp); let mut ecb = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Encrypt, self.k1.as_slice(), None).unwrap();
ecb.pad(false);
if ecb.update(&self.tag, &mut tag_tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tag_tmp).unwrap(), 16);
}
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(aes_ctr_by_key_size(self.k1.len()), Mode::Encrypt, self.k1.as_slice(), Some(&self.tmp)).unwrap()); let _ = self.ctr.replace(Crypter::new(aes_ctr_by_key_size(self.k1.len()), Mode::Encrypt, self.k1.as_slice(), Some(&self.tmp)).unwrap());
} }
@ -178,25 +183,23 @@ impl AesGmacSiv {
return &self.tag; return &self.tag;
} }
#[inline(always)]
fn decrypt_init_internal(&mut self) {
self.tmp[12] &= 0x7f;
let _ = self.ctr.replace(Crypter::new(aes_ctr_by_key_size(self.k1.len()), Mode::Decrypt, self.k1.as_slice(), Some(&self.tmp)).unwrap());
let mut tag_tmp = [0_u8; 32];
let _ = Crypter::new(aes_ecb_by_key_size(self.k1.len()), Mode::Decrypt, self.k1.as_slice(), None).unwrap().update(&self.tag, &mut tag_tmp);
self.tag.copy_from_slice(&tag_tmp[0..16]);
self.tmp[0..8].copy_from_slice(&tag_tmp[0..8]);
self.tmp[8..12].fill(0);
let _ = self.gmac.replace(Crypter::new(aes_gcm_by_key_size(self.k0.len()), Mode::Encrypt, self.k0.as_slice(), Some(&self.tmp[0..12])).unwrap());
}
/// Initialize this cipher for decryption. /// Initialize this cipher for decryption.
/// The supplied tag must be 16 bytes in length. Any other length will panic. /// The supplied tag must be 16 bytes in length. Any other length will panic.
#[inline(always)] #[inline(always)]
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.tag.copy_from_slice(tag); self.tmp[12] &= 0x7f;
self.decrypt_init_internal(); let _ = self.ctr.replace(Crypter::new(aes_ctr_by_key_size(self.k1.len()), Mode::Decrypt, self.k1.as_slice(), Some(&self.tmp)).unwrap());
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);
if ecb.update(tag, &mut tag_tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tag_tmp).unwrap(), 16);
}
self.tag.copy_from_slice(&tag_tmp[0..16]);
tag_tmp[8..12].fill(0);
let _ = self.gmac.replace(Crypter::new(aes_gcm_by_key_size(self.k0.len()), Mode::Encrypt, self.k0.as_slice(), Some(&tag_tmp[0..12])).unwrap());
} }
/// Set additional authenticated data to be checked. /// Set additional authenticated data to be checked.
@ -217,8 +220,7 @@ impl AesGmacSiv {
/// This may be called more than once. /// This may be called more than once.
#[inline(always)] #[inline(always)]
pub fn decrypt_in_place(&mut self, ciphertext_to_plaintext: &mut [u8]) { pub fn decrypt_in_place(&mut self, ciphertext_to_plaintext: &mut [u8]) {
let _ = self.ctr.as_mut().unwrap().update(unsafe { std::slice::from_raw_parts(ciphertext_to_plaintext.as_ptr(), ciphertext_to_plaintext.len()) }, ciphertext_to_plaintext); self.decrypt(unsafe { std::slice::from_raw_parts(ciphertext_to_plaintext.as_ptr(), ciphertext_to_plaintext.len()) }, ciphertext_to_plaintext);
let _ = self.gmac.as_mut().unwrap().aad_update(ciphertext_to_plaintext);
} }
/// Finish decryption and return true if authentication appears valid. /// Finish decryption and return true if authentication appears valid.
@ -228,14 +230,18 @@ impl AesGmacSiv {
let gmac = self.gmac.as_mut().unwrap(); let gmac = self.gmac.as_mut().unwrap();
let _ = gmac.finalize(&mut self.tmp); let _ = gmac.finalize(&mut self.tmp);
let _ = gmac.get_tag(&mut self.tmp); let _ = gmac.get_tag(&mut self.tmp);
unsafe { if (self.tag[8] == self.tmp[0] ^ self.tmp[8])
// tag[8..16] == tmp[0..8] ^ tmp[8..16] && (self.tag[9] == self.tmp[1] ^ self.tmp[9])
let tmp = self.tmp.as_mut_ptr().cast::<u64>(); && (self.tag[10] == self.tmp[2] ^ self.tmp[10])
if *self.tag.as_mut_ptr().cast::<u64>().offset(1) == *tmp ^ *tmp.add(1) { && (self.tag[11] == self.tmp[3] ^ self.tmp[11])
Some(&self.tag) && (self.tag[12] == self.tmp[4] ^ self.tmp[12])
} else { && (self.tag[13] == self.tmp[5] ^ self.tmp[13])
None && (self.tag[14] == self.tmp[6] ^ self.tmp[14])
} && (self.tag[15] == self.tmp[7] ^ self.tmp[15])
{
Some(&self.tag)
} else {
None
} }
} }
} }

View file

@ -73,6 +73,7 @@ fn salsa_poly_create(secret: &SymmetricSecret, header: &PacketHeader, packet_siz
key.0[20] ^= packet_size as u8; key.0[20] ^= packet_size as u8;
let mut salsa = Salsa::<12>::new(&key.0, &header.id); let mut salsa = Salsa::<12>::new(&key.0, &header.id);
let mut poly1305_key = [0_u8; 32]; let mut poly1305_key = [0_u8; 32];
salsa.crypt_in_place(&mut poly1305_key); salsa.crypt_in_place(&mut poly1305_key);

1078
zerotier-system-service/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
use std::hash::Hash;
use std::sync::{Arc, Weak};
use crate::udp::BoundUdpSocket;
/// Local socket wrapper to provide to the core.
///
/// This implements very fast hash and equality in terms of an arbitrary unique ID assigned at
/// construction and holds a weak reference to the bound socket so dead sockets will silently
/// cease to exist or work. This also means that this code can check the weak count to determine
/// if the core is currently holding/using a socket for any reason.
#[derive(Clone)]
pub struct LocalSocket(pub Weak<BoundUdpSocket>, pub usize);
impl LocalSocket {
/// Returns true if the wrapped socket appears to be in use by the core.
#[inline(always)]
pub fn in_use(&self) -> bool {
self.0.weak_count() > 0
}
#[inline(always)]
pub fn socket(&self) -> Option<Arc<BoundUdpSocket>> {
self.0.upgrade()
}
}
impl PartialEq for LocalSocket {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl Eq for LocalSocket {}
impl Hash for LocalSocket {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.1.hash(state)
}
}
impl ToString for LocalSocket {
fn to_string(&self) -> String {
if let Some(s) = self.0.upgrade() {
s.address.to_string()
} else {
"(closed socket)".into()
}
}
}

View file

@ -7,6 +7,7 @@ pub mod getifaddrs;
pub mod jsonformatter; pub mod jsonformatter;
pub mod localconfig; pub mod localconfig;
pub mod localinterface; pub mod localinterface;
pub mod localsocket;
pub mod service; pub mod service;
pub mod udp; pub mod udp;
pub mod utils; pub mod utils;

View file

@ -2,10 +2,9 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::error::Error; use std::error::Error;
use std::hash::Hash;
use std::path::Path; use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Weak}; use std::sync::Arc;
use zerotier_network_hypervisor::vl1::*; use zerotier_network_hypervisor::vl1::*;
use zerotier_network_hypervisor::vl2::*; use zerotier_network_hypervisor::vl2::*;
@ -17,7 +16,8 @@ use tokio::time::Duration;
use crate::datadir::DataDir; use crate::datadir::DataDir;
use crate::localinterface::LocalInterface; use crate::localinterface::LocalInterface;
use crate::udp::{BoundUdpPort, BoundUdpSocket}; use crate::localsocket::LocalSocket;
use crate::udp::*;
use crate::utils::{ms_monotonic, ms_since_epoch}; use crate::utils::{ms_monotonic, ms_since_epoch};
const UDP_UPDATE_BINDINGS_INTERVAL_MS: Duration = Duration::from_millis(2500); const UDP_UPDATE_BINDINGS_INTERVAL_MS: Duration = Duration::from_millis(2500);
@ -261,51 +261,3 @@ impl SystemInterface for ServiceImpl {
impl SwitchInterface for ServiceImpl {} impl SwitchInterface for ServiceImpl {}
impl Interface for ServiceImpl {} impl Interface for ServiceImpl {}
/// Local socket wrapper to provide to the core.
///
/// This implements very fast hash and equality in terms of an arbitrary unique ID assigned at
/// construction and holds a weak reference to the bound socket so dead sockets will silently
/// cease to exist or work. This also means that this code can check the weak count to determine
/// if the core is currently holding/using a socket for any reason.
#[derive(Clone)]
pub struct LocalSocket(Weak<BoundUdpSocket>, usize);
impl LocalSocket {
/// Returns true if the wrapped socket appears to be in use by the core.
#[inline(always)]
pub fn in_use(&self) -> bool {
self.0.weak_count() > 0
}
#[inline(always)]
pub fn socket(&self) -> Option<Arc<BoundUdpSocket>> {
self.0.upgrade()
}
}
impl PartialEq for LocalSocket {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl Eq for LocalSocket {}
impl Hash for LocalSocket {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.1.hash(state)
}
}
impl ToString for LocalSocket {
fn to_string(&self) -> String {
if let Some(s) = self.0.upgrade() {
s.address.to_string()
} else {
"(closed socket)".into()
}
}
}