use crate::error::{CryptoKitError, Result};
use crate::symmetric::AuthenticatedCipher;
extern "C" {
#[link_name = "aes_gcm_encrypt"]
fn swift_aes_gcm_encrypt(
key: *const u8,
key_len: i32,
nonce: *const u8,
nonce_len: i32,
plaintext: *const u8,
plaintext_len: i32,
ciphertext: *mut u8,
ciphertext_len: *mut i32,
) -> i32;
#[link_name = "aes_gcm_decrypt"]
fn swift_aes_gcm_decrypt(
key: *const u8,
key_len: i32,
nonce: *const u8,
nonce_len: i32,
ciphertext: *const u8,
ciphertext_len: i32,
plaintext: *mut u8,
plaintext_len: *mut i32,
) -> i32;
#[link_name = "aes_gcm_encrypt_with_aad"]
fn swift_aes_gcm_encrypt_with_aad(
key: *const u8,
key_len: i32,
nonce: *const u8,
nonce_len: i32,
plaintext: *const u8,
plaintext_len: i32,
aad: *const u8,
aad_len: i32,
ciphertext: *mut u8,
ciphertext_len: *mut i32,
) -> i32;
#[link_name = "aes_gcm_decrypt_with_aad"]
fn swift_aes_gcm_decrypt_with_aad(
key: *const u8,
key_len: i32,
nonce: *const u8,
nonce_len: i32,
ciphertext: *const u8,
ciphertext_len: i32,
aad: *const u8,
aad_len: i32,
plaintext: *mut u8,
plaintext_len: *mut i32,
) -> i32;
#[link_name = "generate_symmetric_key"]
fn swift_generate_symmetric_key(size_bits: i32, key_data: *mut u8) -> i32;
#[link_name = "generate_aes_gcm_nonce"]
fn swift_generate_aes_gcm_nonce(nonce_data: *mut u8) -> i32;
}
#[derive(Clone)]
pub struct AESKey {
pub(crate) bytes: Vec<u8>,
}
impl AESKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
match bytes.len() {
16 | 24 | 32 => Ok(Self {
bytes: bytes.to_vec(),
}),
_ => Err(CryptoKitError::InvalidKey),
}
}
pub fn generate(size: AESKeySize) -> Result<Self> {
let len = match size {
AESKeySize::AES128 => 16,
AESKeySize::AES192 => 24,
AESKeySize::AES256 => 32,
};
unsafe {
let mut bytes = vec![0u8; len];
let result = swift_generate_symmetric_key(
(len * 8) as i32, bytes.as_mut_ptr(),
);
if result == 0 {
Ok(Self { bytes })
} else {
Err(CryptoKitError::KeyGenerationFailed)
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum AESKeySize {
AES128,
AES192,
AES256,
}
#[derive(Clone)]
pub struct AESGCMNonce {
pub(crate) bytes: [u8; 12],
}
impl AESGCMNonce {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 12 {
return Err(CryptoKitError::InvalidNonce);
}
let mut nonce_bytes = [0u8; 12];
nonce_bytes.copy_from_slice(bytes);
Ok(Self { bytes: nonce_bytes })
}
pub fn generate() -> Result<Self> {
unsafe {
let mut bytes = [0u8; 12];
let result = swift_generate_aes_gcm_nonce(bytes.as_mut_ptr());
if result == 0 {
Ok(Self { bytes })
} else {
Err(CryptoKitError::NonceGenerationFailed)
}
}
}
}
pub struct AesGcm;
impl AuthenticatedCipher for AesGcm {
type Key = AESKey;
type Nonce = AESGCMNonce;
const TAG_SIZE: usize = 16;
fn seal_to(
key: &Self::Key,
nonce: &Self::Nonce,
plaintext: &[u8],
ciphertext: &mut [u8],
) -> Result<usize> {
if ciphertext.len() < plaintext.len() + 16 {
return Err(CryptoKitError::OutputBufferTooSmall(
plaintext.len(),
plaintext.len() + 16,
));
}
unsafe {
let mut ciphertext_len: i32 = 0;
let result = swift_aes_gcm_encrypt(
key.bytes.as_ptr(),
key.bytes.len() as i32,
nonce.bytes.as_ptr(),
nonce.bytes.len() as i32,
plaintext.as_ptr(),
plaintext.len() as i32,
ciphertext.as_mut_ptr(),
&mut ciphertext_len,
);
if result == 0 {
Ok(ciphertext_len as usize)
} else {
Err(CryptoKitError::EncryptionFailed)
}
}
}
fn open_to(
key: &Self::Key,
nonce: &Self::Nonce,
ciphertext: &[u8],
plaintext: &mut [u8],
) -> Result<usize> {
if ciphertext.len() < 16 {
return Err(CryptoKitError::InvalidInput(
"Ciphertext too short".to_string(),
));
}
if plaintext.len() < ciphertext.len() - 16 {
return Err(CryptoKitError::OutputBufferTooSmall(
ciphertext.len(),
ciphertext.len() - 16,
));
}
unsafe {
let mut plaintext_len = 0i32;
let result = swift_aes_gcm_decrypt(
key.bytes.as_ptr(),
key.bytes.len() as i32,
nonce.bytes.as_ptr(),
nonce.bytes.len() as i32,
ciphertext.as_ptr(),
ciphertext.len() as i32,
plaintext.as_mut_ptr(),
&mut plaintext_len,
);
if result == 0 {
Ok(plaintext_len as usize)
} else {
Err(CryptoKitError::DecryptionFailed)
}
}
}
fn seal_to_with_aad(
key: &Self::Key,
nonce: &Self::Nonce,
plaintext: &[u8],
aad: &[u8],
ciphertext: &mut [u8],
) -> Result<usize> {
if ciphertext.len() < plaintext.len() + 16 {
return Err(CryptoKitError::OutputBufferTooSmall(
plaintext.len(),
plaintext.len() + 16,
));
}
unsafe {
let mut ciphertext_len = 0i32;
let result = swift_aes_gcm_encrypt_with_aad(
key.bytes.as_ptr(),
key.bytes.len() as i32,
nonce.bytes.as_ptr(),
nonce.bytes.len() as i32,
plaintext.as_ptr(),
plaintext.len() as i32,
aad.as_ptr(),
aad.len() as i32,
ciphertext.as_mut_ptr(),
&mut ciphertext_len,
);
if result == 0 {
Ok(ciphertext_len as usize)
} else {
Err(CryptoKitError::EncryptionFailed)
}
}
}
fn open_to_with_aad(
key: &Self::Key,
nonce: &Self::Nonce,
ciphertext: &[u8],
aad: &[u8],
plaintext: &mut [u8],
) -> Result<usize> {
if ciphertext.len() < 16 {
return Err(CryptoKitError::InvalidInput(
"Ciphertext too short".to_string(),
));
}
if plaintext.len() < ciphertext.len() - 16 {
return Err(CryptoKitError::OutputBufferTooSmall(
ciphertext.len(),
ciphertext.len() - 16,
));
}
unsafe {
let mut plaintext_len = 0i32;
let result = swift_aes_gcm_decrypt_with_aad(
key.bytes.as_ptr(),
key.bytes.len() as i32,
nonce.bytes.as_ptr(),
nonce.bytes.len() as i32,
ciphertext.as_ptr(),
ciphertext.len() as i32,
aad.as_ptr(),
aad.len() as i32,
plaintext.as_mut_ptr(),
&mut plaintext_len,
);
if result == 0 {
Ok(plaintext_len as usize)
} else {
Err(CryptoKitError::DecryptionFailed)
}
}
}
}
pub fn aes_gcm_encrypt(key: &[u8], nonce: &[u8], plaintext: &[u8]) -> Result<Vec<u8>> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::seal(&key, &nonce, plaintext)
}
pub fn aes_gcm_encrypt_to(
key: &[u8],
nonce: &[u8],
plaintext: &[u8],
ciphertext: &mut [u8],
) -> Result<usize> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::seal_to(&key, &nonce, plaintext, ciphertext)
}
pub fn aes_gcm_decrypt(key: &[u8], nonce: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::open(&key, &nonce, ciphertext)
}
pub fn aes_gcm_decrypt_to(
key: &[u8],
nonce: &[u8],
ciphertext: &[u8],
plaintext: &mut [u8],
) -> Result<usize> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::open_to(&key, &nonce, ciphertext, plaintext)
}
pub fn aes_gcm_encrypt_with_aad(
key: &[u8],
nonce: &[u8],
plaintext: &[u8],
aad: &[u8],
) -> Result<Vec<u8>> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::seal_with_aad(&key, &nonce, plaintext, aad)
}
pub fn aes_gcm_encrypt_to_with_aad(
key: &[u8],
nonce: &[u8],
plaintext: &[u8],
aad: &[u8],
ciphertext: &mut [u8],
) -> Result<usize> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::seal_to_with_aad(&key, &nonce, plaintext, aad, ciphertext)
}
pub fn aes_gcm_decrypt_with_aad(
key: &[u8],
nonce: &[u8],
ciphertext: &[u8],
aad: &[u8],
) -> Result<Vec<u8>> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::open_with_aad(&key, &nonce, ciphertext, aad)
}
pub fn aes_gcm_decrypt_to_with_aad(
key: &[u8],
nonce: &[u8],
ciphertext: &[u8],
aad: &[u8],
plaintext: &mut [u8],
) -> Result<usize> {
let key = AESKey::from_bytes(key)?;
let nonce = AESGCMNonce::from_bytes(nonce)?;
AesGcm::open_to_with_aad(&key, &nonce, ciphertext, aad, plaintext)
}