2021-10-15 03:44:56 -07:00
|
|
|
use {
|
2021-10-17 08:16:18 -07:00
|
|
|
ed25519_dalek::SecretKey as SigningKey,
|
|
|
|
solana_sdk::pubkey::Pubkey,
|
|
|
|
std::convert::TryInto,
|
2021-10-15 03:44:56 -07:00
|
|
|
zeroize::Zeroize,
|
2021-10-14 09:19:22 -07:00
|
|
|
};
|
2021-10-17 08:16:18 -07:00
|
|
|
#[cfg(not(target_arch = "bpf"))]
|
|
|
|
use {
|
|
|
|
aes_gcm::{aead::Aead, Aes128Gcm, NewAead},
|
|
|
|
rand::{CryptoRng, rngs::OsRng, Rng, RngCore},
|
|
|
|
sha3::{Digest, Sha3_256},
|
|
|
|
};
|
2021-10-08 06:12:54 -07:00
|
|
|
|
2021-10-17 08:16:18 -07:00
|
|
|
struct AES;
|
2021-10-07 15:21:31 -07:00
|
|
|
impl AES {
|
2021-10-11 12:16:29 -07:00
|
|
|
#[cfg(not(target_arch = "bpf"))]
|
|
|
|
#[allow(clippy::new_ret_no_self)]
|
2021-10-17 08:16:18 -07:00
|
|
|
fn keygen<T: RngCore + CryptoRng>(rng: &mut T) -> AesKey {
|
2021-10-08 06:12:54 -07:00
|
|
|
let random_bytes = OsRng.gen::<[u8; 16]>();
|
2021-10-17 08:16:18 -07:00
|
|
|
AesKey(random_bytes)
|
2021-10-07 15:21:31 -07:00
|
|
|
}
|
|
|
|
|
2021-10-11 12:16:29 -07:00
|
|
|
#[cfg(not(target_arch = "bpf"))]
|
2021-10-17 08:16:18 -07:00
|
|
|
fn encrypt(sk: &AesKey, amount: u64) -> AesCiphertext {
|
|
|
|
let plaintext = amount.to_le_bytes();
|
|
|
|
let nonce = OsRng.gen::<[u8; 12]>();
|
2021-10-08 06:12:54 -07:00
|
|
|
|
2021-10-17 08:16:18 -07:00
|
|
|
// TODO: it seems like encryption cannot fail, but will need to double check
|
|
|
|
let ciphertext = Aes128Gcm::new(&sk.0.into())
|
|
|
|
.encrypt(&nonce.into(), plaintext.as_ref()).unwrap();
|
2021-10-08 06:12:54 -07:00
|
|
|
|
2021-10-17 08:16:18 -07:00
|
|
|
AesCiphertext {
|
|
|
|
nonce,
|
|
|
|
ciphertext: ciphertext.try_into().unwrap(),
|
|
|
|
}
|
2021-10-07 15:21:31 -07:00
|
|
|
}
|
|
|
|
|
2021-10-11 12:16:29 -07:00
|
|
|
#[cfg(not(target_arch = "bpf"))]
|
2021-10-17 08:16:18 -07:00
|
|
|
fn decrypt(sk: &AesKey, ct: &AesCiphertext) -> Option<u64> {
|
|
|
|
let plaintext = Aes128Gcm::new(&sk.0.into())
|
|
|
|
.decrypt(&ct.nonce.into(), ct.ciphertext.as_ref());
|
2021-10-08 06:12:54 -07:00
|
|
|
|
2021-10-17 08:16:18 -07:00
|
|
|
if let Ok(plaintext) = plaintext {
|
|
|
|
let amount_bytes: [u8; 8] = plaintext.try_into().unwrap();
|
|
|
|
Some(u64::from_le_bytes(amount_bytes))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2021-10-07 15:21:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 12:16:29 -07:00
|
|
|
#[derive(Debug, Zeroize)]
|
2021-10-17 08:16:18 -07:00
|
|
|
pub struct AesKey([u8; 16]);
|
|
|
|
impl AesKey {
|
|
|
|
pub fn new(signing_key: &SigningKey, address: &Pubkey) -> Self {
|
|
|
|
let mut hashable = [0_u8; 64];
|
|
|
|
hashable[..32].copy_from_slice(&signing_key.to_bytes());
|
|
|
|
hashable[32..].copy_from_slice(&address.to_bytes());
|
|
|
|
|
|
|
|
let mut hasher = Sha3_256::new();
|
|
|
|
hasher.update(hashable);
|
|
|
|
|
|
|
|
let result: [u8; 16] = hasher.finalize()[..16].try_into().unwrap();
|
|
|
|
AesKey(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn random<T: RngCore + CryptoRng>(rng: &mut T) -> Self {
|
|
|
|
AES::keygen(&mut rng)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn encrypt(&self, amount: u64) -> AesCiphertext {
|
2021-10-07 15:21:31 -07:00
|
|
|
AES::encrypt(self, amount)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-08 06:12:54 -07:00
|
|
|
#[derive(Debug)]
|
2021-10-17 08:16:18 -07:00
|
|
|
pub struct AesCiphertext {
|
|
|
|
pub nonce: [u8; 12],
|
|
|
|
pub ciphertext: [u8; 24],
|
2021-10-07 15:21:31 -07:00
|
|
|
}
|
2021-10-17 08:16:18 -07:00
|
|
|
impl AesCiphertext {
|
|
|
|
pub fn decrypt(&self, key: &AesKey) -> Option<u64> {
|
|
|
|
AES::decrypt(key, self)
|
2021-10-14 09:56:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-08 06:12:54 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_aes_encrypt_decrypt_correctness() {
|
2021-10-17 08:16:18 -07:00
|
|
|
let key = AesKey::random(&mut OsRng);
|
2021-10-08 06:12:54 -07:00
|
|
|
let amount = 55;
|
|
|
|
|
2021-10-17 08:16:18 -07:00
|
|
|
let ct = key.encrypt(amount);
|
|
|
|
let decrypted_amount = ct.decrypt(&key).unwrap();
|
2021-10-08 06:12:54 -07:00
|
|
|
|
|
|
|
assert_eq!(amount, decrypted_amount);
|
|
|
|
}
|
|
|
|
}
|