Skip to content

Commit

Permalink
work around RustCrypto/AEADs#410
Browse files Browse the repository at this point in the history
We're trying to bring the AES version up so we can do CBC
(required for FIDO2) but unfortunately the aes-gcm-siv crate
is locked to an outdated version of AES, and this is blocking
on a type that is missing in the `block-ciphers` crate.

For now, we're using a patched version of aes-gcm-siv from
rozbb's repo, which allows us to move forward, but this needs
to be reverted once a new version of the official crate is patched.
  • Loading branch information
bunnie authored and nworbnhoj committed Jun 1, 2022
1 parent b0ee0ce commit 95784b6
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 33 deletions.
7 changes: 4 additions & 3 deletions services/pddb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ trng = {path = "../trng"}
spinor = {path = "../spinor"}
aes = {path="../aes"}
root-keys = {path="../root-keys"}
cipher = "0.3.0"
cipher = "0.4.2"
bitfield = "0.13.2"
aes-gcm-siv = "0.10.3"
#aes-gcm-siv = {version = "0.10.3", default-features = false, features = ["alloc"]}
aes-gcm-siv = {git="https://github.com/rozbb/AEADs.git", branch="update-cipher"}
llio = {path="../llio"}
subtle = {version = "2.4.1", default-features = false}
tts-frontend = {path="../tts"}
Expand All @@ -37,7 +38,7 @@ zeroize = "1.3.0"
zeroize_derive = "1.1.0"

# bcrypt
blowfish = { version = "0.8.0", features = ["bcrypt"] }
blowfish = { version = "0.9.1", features = ["bcrypt"] }

# UX (for password entry and notifications)
gam = {path="../gam"}
Expand Down
6 changes: 3 additions & 3 deletions services/pddb/src/backend/basis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ use super::*;
use core::ops::{Deref, DerefMut};
use core::mem::size_of;
use std::convert::TryInto;
use aes_gcm_siv::{Aes256GcmSiv, Key};
use aes_gcm_siv::{AesGcmSiv, Key};
use aes_gcm_siv::aead::NewAead;
use aes::Aes256;
use aes::cipher::{KeyInit, generic_array::GenericArray};
Expand Down Expand Up @@ -983,7 +983,7 @@ pub(crate) struct BasisCacheEntry {
/// expressed as a number that needs to be multiplied by DICT_VSIZE to arrive at a virtual address
pub free_dict_offset: Option<u32>,
/// the cipher for the basis
pub cipher: Aes256GcmSiv,
pub cipher: AesGcmSiv::<Aes256>,
/// derived cipher for encrypting PTEs -- cache it, so we can save the time cost of constructing the cipher key schedule
pub cipher_ecb: Aes256,
/// raw AES key -- needed because we have to use this to derive commitment keys for the basis root record, to work around AES-GCM-SIV salamanders
Expand All @@ -1010,7 +1010,7 @@ impl BasisCacheEntry {
/// discover the location of the `large_alloc_ptr`.
pub(crate) fn mount(hw: &mut PddbOs, name: &str, key: &BasisKeys, lazy: bool, policy: BasisRetentionPolicy) -> Option<BasisCacheEntry> {
if let Some(basis_map) = hw.pt_scan_key(&key.pt, name) {
let cipher = Aes256GcmSiv::new(Key::from_slice(&key.data));
let cipher = AesGcmSiv::<Aes256>::new(Key::from_slice(&key.data));
let aad = hw.data_aad(name);
// get the first page, where the basis root is guaranteed to be
if let Some(root_page) = basis_map.get(&VirtAddr::new(VPAGE_SIZE as u64).unwrap()) {
Expand Down
6 changes: 3 additions & 3 deletions services/pddb/src/backend/bcrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ pub fn bcrypt(cost: u32, salt: &[u8], pw: &str, output: &mut [u8]) {
for i in 0..3 {
let i: usize = i * 2;
for _ in 0..64 {
let (l, r) = state.bc_encrypt(ctext[i], ctext[i + 1]);
ctext[i] = l;
ctext[i + 1] = r;
let lr = state.bc_encrypt([ctext[i], ctext[i + 1]]);
ctext[i] = lr[0];
ctext[i + 1] = lr[1];
}

let buf = ctext[i].to_be_bytes();
Expand Down
19 changes: 10 additions & 9 deletions services/pddb/src/backend/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use super::*;
use std::num::NonZeroU32;
use core::ops::{Deref, DerefMut};
use core::mem::size_of;
use aes_gcm_siv::Aes256GcmSiv;
use aes_gcm_siv::AesGcmSiv;
use aes::Aes256;
use std::collections::{HashMap, BinaryHeap, HashSet};
use std::io::{Result, Error, ErrorKind};
use bitfield::bitfield;
Expand Down Expand Up @@ -85,7 +86,7 @@ impl DictCacheEntry {
/// Requires a descriptor for the hardware, and our virtual to physical page mapping.
/// Does not overwrite existing cache entries, if they already exist -- only loads in ones that are missing.
/// Todo: condense routines in common with ensure_key_entry() to make it easier to maintain.
pub fn fill(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv) -> VirtAddr {
pub fn fill(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>) -> VirtAddr {
let mut try_entry = 1;
let mut key_count = 0;
let mut alloc_top = VirtAddr::new(LARGE_POOL_START).unwrap();
Expand Down Expand Up @@ -192,7 +193,7 @@ impl DictCacheEntry {
}
/// merges the list of keys in this dict cache entry into a merge_list.
/// The `merge_list` is used because keys are presented as a union across all open basis.
pub(crate) fn key_list(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv, merge_list: &mut HashSet<String>) {
pub(crate) fn key_list(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>, merge_list: &mut HashSet<String>) {
// ensure that the key cache is filled
if self.keys.len() < self.key_count as usize {
self.fill(hw, v2p_map, cipher);
Expand All @@ -208,7 +209,7 @@ impl DictCacheEntry {
/// This shares a lot of code with the fill() routine -- we should condense the common routines
/// to make this easier to maintain. Returns false if the disk was searched and no key was found; true
/// if cache is hot or key was found on search.
pub(crate) fn ensure_key_entry(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv,
pub(crate) fn ensure_key_entry(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>,
name_str: &str) -> bool {
// only fill if the key isn't in the cache.
if !self.keys.contains_key(name_str) {
Expand Down Expand Up @@ -279,7 +280,7 @@ impl DictCacheEntry {
}
}
}
fn try_fill_small_key(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv,
fn try_fill_small_key(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>,
data_cache: &mut PlaintextCache, key_name: &str) {
if let Some(kcache) = self.keys.get_mut(key_name) {
if let Some(pool_index) = small_storage_index_from_key(&kcache, self.index) {
Expand Down Expand Up @@ -350,7 +351,7 @@ impl DictCacheEntry {
/// specific dictionary in a named basis. In all of these cases, the Basis resolver will have had to find the
/// correct DictCacheEntry and issue the `key_update` to it; for multiple updates, then multiple calls to
/// multiple DictCacheEntry are required.
pub fn key_update(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv,
pub fn key_update(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>,
name: &str, data: &[u8], offset: usize, alloc_hint:Option<usize>, truncate: bool, large_alloc_ptr: PageAlignedVa) -> Result <PageAlignedVa> {
self.age = self.age.saturating_add(1);
self.clean = false;
Expand Down Expand Up @@ -680,7 +681,7 @@ impl DictCacheEntry {
/// Used to remove a key from the dictionary. If you call it with a non-existent key,
/// the routine has no effect, and does not report an error. Small keys are not immediately
/// overwritten in paranoid mode, but large keys are.
pub fn key_remove(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv,
pub fn key_remove(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>,
name_str: &str, paranoid: bool) {
if paranoid {
// large records are paranoid-erased, by default, because of the pool-reuse problem.
Expand Down Expand Up @@ -793,7 +794,7 @@ impl DictCacheEntry {
///
/// Observation: given the dictionary index and the small key pool index, we know exactly
/// the virtual address of the data pool.
pub(crate) fn sync_small_pool(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv) -> bool {
pub(crate) fn sync_small_pool(&mut self, hw: &mut PddbOs, v2p_map: &mut HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>) -> bool {
for (index, entry) in self.small_pool.iter_mut().enumerate() {
if !entry.clean {
let pool_vaddr = VirtAddr::new(small_storage_base_vaddr_from_indices(self.index, index)).unwrap();
Expand Down Expand Up @@ -1176,7 +1177,7 @@ pub(crate) struct PlaintextCache {
pub(crate) tag: Option<PhysPage>,
}
impl PlaintextCache {
pub fn fill(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &Aes256GcmSiv, aad: &[u8],
pub fn fill(&mut self, hw: &mut PddbOs, v2p_map: &HashMap::<VirtAddr, PhysPage>, cipher: &AesGcmSiv::<Aes256>, aad: &[u8],
req_vaddr: VirtAddr
) {
if let Some(pp) = v2p_map.get(&req_vaddr) {
Expand Down
29 changes: 14 additions & 15 deletions services/pddb/src/backend/hw.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::convert::TryInto;

use crate::*;
use aes_gcm_siv::{Aes256GcmSiv, Nonce, Key, Tag};
use aes_gcm_siv::{AesGcmSiv, Nonce, Key, Tag};
use aes_gcm_siv::aead::{Aead, NewAead, Payload};
use aes::{Aes256, Block, BLOCK_SIZE};
use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray};
Expand Down Expand Up @@ -460,7 +460,7 @@ impl PddbOs {
pp.set_space_state(SpaceState::Used);
// handle conflicting journal versions here
if let Some(prev_page) = map.get(&pte.vaddr()) {
let cipher = Aes256GcmSiv::new(Key::from_slice(key));
let cipher = AesGcmSiv::<Aes256>::new(Key::from_slice(key));
let aad = self.data_aad(basis_name);
let prev_data = self.data_decrypt_page(&cipher, &aad, prev_page);
let new_data = self.data_decrypt_page(&cipher, &aad, &pp);
Expand Down Expand Up @@ -657,7 +657,7 @@ impl PddbOs {
self.syskey_ensure();
if let Some(system_basis_key) = &self.system_basis_key {
let key = Key::from_slice(&system_basis_key.data);
let cipher = Aes256GcmSiv::new(key);
let cipher = AesGcmSiv::<Aes256>::new(key);
let nonce_array = self.entropy.borrow_mut().get_nonce();
let nonce = Nonce::from_slice(&nonce_array);
let fs_ser: &[u8] = fs.deref();
Expand Down Expand Up @@ -857,7 +857,7 @@ impl PddbOs {
aad: &aad,
};
let key = Key::from_slice(&system_key.data);
let cipher = Aes256GcmSiv::new(key);
let cipher = AesGcmSiv::<Aes256>::new(key);
match cipher.decrypt(Nonce::from_slice(&fscb_slice[page_start..page_start + size_of::<Nonce>()]), payload) {
Ok(msg) => {
log::info!("decrypted: {}, FastSpace size: {}", msg.len(), size_of::<FastSpace>());
Expand Down Expand Up @@ -1203,7 +1203,7 @@ impl PddbOs {
/// returns a decrypted page that still includes the journal number at the very beginning
/// We don't clip it off because it would require re-allocating a vector, and it's cheaper (although less elegant) to later
/// just index past it.
pub(crate) fn data_decrypt_page(&self, cipher: &Aes256GcmSiv, aad: &[u8], page: &PhysPage) -> Option<Vec::<u8>> {
pub(crate) fn data_decrypt_page(&self, cipher: &AesGcmSiv::<Aes256>, aad: &[u8], page: &PhysPage) -> Option<Vec::<u8>> {
let ct_slice = &self.pddb_mr.as_slice()[
self.data_phys_base.as_usize() + page.page_number() as usize * PAGE_SIZE ..
self.data_phys_base.as_usize() + (page.page_number() as usize + 1) * PAGE_SIZE];
Expand Down Expand Up @@ -1278,7 +1278,7 @@ impl PddbOs {
log::debug!("found kcom_nonce of {:x?}", nonce_comm);

let (kenc, kcom) = self.kcom_func(key.try_into().unwrap(), &nonce_comm);
let cipher = Aes256GcmSiv::new(Key::from_slice(&kenc));
let cipher = AesGcmSiv::<Aes256>::new(Key::from_slice(&kenc));

// Attempt decryption. This is None on failure
let plaintext = cipher.decrypt(
Expand All @@ -1298,7 +1298,7 @@ impl PddbOs {
}

/// `data` includes the journal entry on top. The data passed in must be exactly one vpage plus the journal entry
pub(crate) fn data_encrypt_and_patch_page(&self, cipher: &Aes256GcmSiv, aad: &[u8], data: &mut [u8], pp: &PhysPage) {
pub(crate) fn data_encrypt_and_patch_page(&self, cipher: &AesGcmSiv::<Aes256>, aad: &[u8], data: &mut [u8], pp: &PhysPage) {
assert!(data.len() == VPAGE_SIZE + size_of::<JournalType>(), "did not get a page-sized region to patch");
let j = JournalType::from_le_bytes(data[..size_of::<JournalType>()].try_into().unwrap()).saturating_add(1);
for (&src, dst) in j.to_le_bytes().iter().zip(data[..size_of::<JournalType>()].iter_mut()) { *dst = src; }
Expand Down Expand Up @@ -1328,7 +1328,7 @@ impl PddbOs {
self.trng_slice(&mut kcom_nonce);
// generates the encryption and commit keys
let (kenc, kcom) = self.kcom_func(key.try_into().unwrap(), &kcom_nonce);
let cipher = Aes256GcmSiv::new(Key::from_slice(&kenc));
let cipher = AesGcmSiv::<Aes256>::new(Key::from_slice(&kenc));
let ciphertext = cipher.encrypt(
&nonce,
Payload {
Expand Down Expand Up @@ -1438,7 +1438,6 @@ impl PddbOs {
/// The number of servers that can connect to the Spinor crate is strictly tracked, so we borrow a reference
/// to the Spinor object allocated to the PDDB implementation for this operation.
pub(crate) fn pddb_format(&mut self, fast: bool, progress: Option<&modals::Modals>) -> Result<()> {
use cipher::BlockDecrypt;
if !self.rootkeys.is_initialized().unwrap() {
return Err(Error::new(ErrorKind::Unsupported, "Root keys are not initialized; cannot format a PDDB without root keys!"));
}
Expand Down Expand Up @@ -1958,10 +1957,10 @@ impl PddbOs {
aad_v2: &Vec::<u8>,
key_v1: &[u8; AES_KEYSIZE], // needed to decrypt page with commit
cipher_pt_v1: &Aes256,
cipher_data_v1: &Aes256GcmSiv,
cipher_data_v1: &AesGcmSiv::<Aes256>,
key_data_v2: &[u8; AES_KEYSIZE], // this is needed because we have to do a key commitment
cipher_pt_v2: &Aes256,
cipher_data_v2: &Aes256GcmSiv,
cipher_data_v2: &AesGcmSiv::<Aes256>,
used_pages: &mut BinaryHeap::<Reverse<u32>>,
) -> bool {
let blank = [0xffu8; aes::BLOCK_SIZE];
Expand Down Expand Up @@ -2121,7 +2120,7 @@ impl PddbOs {
// build the ECB cipher for page table entries, and data cipher for data pages
self.cipher_ecb = Some(Aes256::new(GenericArray::from_slice(&system_basis_key_pt)));
let cipher_v2 = Aes256::new(GenericArray::from_slice(&system_basis_key_pt)); // a second copy for patching the page table later in this routine interior mutability blah blah work around oops
let data_cipher_v2 = Aes256GcmSiv::new(Key::from_slice(&system_basis_key));
let data_cipher_v2 = AesGcmSiv::<Aes256>::new(Key::from_slice(&system_basis_key));
let aad_v2 = self.data_aad(PDDB_DEFAULT_SYSTEM_BASIS);
// now wrap the key for storage
let wrapped_key = self.rootkeys.wrap_key(&system_basis_key).expect("Internal error wrapping our encryption key");
Expand Down Expand Up @@ -2151,7 +2150,7 @@ impl PddbOs {

// now we have a copy of the AES key necessary to re-encrypt all the basis
// build the data cipher for v1 pages
let data_cipher_v1 = Aes256GcmSiv::new(Key::from_slice(&system_key_v1));
let data_cipher_v1 = AesGcmSiv::<Aes256>::new(Key::from_slice(&system_key_v1));
let aad_v1 = data_aad_v1(&self, PDDB_DEFAULT_SYSTEM_BASIS);

// track used pages so we can create the FSCB at the end
Expand Down Expand Up @@ -2208,10 +2207,10 @@ impl PddbOs {
let basis_aad_v1 = data_aad_v1(&self, bname.first().as_str());
let basis_aad_v2 = self.data_aad(bname.first().as_str());
let basis_pt_cipher_v1 = Aes256::new(GenericArray::from_slice(&basis_key_v1));
let basis_data_cipher_v1 = Aes256GcmSiv::new(Key::from_slice(&basis_key_v1));
let basis_data_cipher_v1 = AesGcmSiv::<Aes256>::new(Key::from_slice(&basis_key_v1));
let basis_keys = self.basis_derive_key(bname.first().as_str(), pw.as_str().unwrap_or("UTF8 error"));
let basis_pt_cipher_2 = Aes256::new(GenericArray::from_slice(&basis_keys.pt));
let basis_data_cipher_2 = Aes256GcmSiv::new(Key::from_slice(&basis_keys.data));
let basis_data_cipher_2 = AesGcmSiv::<Aes256>::new(Key::from_slice(&basis_keys.data));
// perform the migration
if self.migration_v1_to_v2_inner(
&basis_aad_v1, &basis_aad_v2,
Expand Down

0 comments on commit 95784b6

Please sign in to comment.