|
@@ -13,6 +13,7 @@ use aes_gcm::Aes128Gcm;
|
|
|
use curve25519_dalek::scalar::Scalar;
|
|
|
use rand::RngCore;
|
|
|
use std::convert::TryInto;
|
|
|
+use subtle::ConstantTimeEq;
|
|
|
|
|
|
/// Each bridge information line is serialized into this many bytes
|
|
|
pub const BRIDGE_BYTES: usize = 220;
|
|
@@ -194,6 +195,16 @@ impl BridgeTable {
|
|
|
plaintext.as_slice().try_into().unwrap(),
|
|
|
))
|
|
|
}
|
|
|
+
|
|
|
+ /// Decrypt an individual encrypted bucket, given its id and key
|
|
|
+ pub fn decrypt_bucket_id(
|
|
|
+ &self,
|
|
|
+ id: u32,
|
|
|
+ key: &[u8; 16],
|
|
|
+ ) -> Result<[BridgeLine; MAX_BRIDGES_PER_BUCKET], aead::Error> {
|
|
|
+ let encbucket = self.encbuckets[id as usize];
|
|
|
+ BridgeTable::decrypt_bucket(key, &encbucket)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Unit tests that require access to the testing-only function
|
|
@@ -225,18 +236,15 @@ mod tests {
|
|
|
btable.encrypt_table();
|
|
|
// Try to decrypt a 1-bridge bucket
|
|
|
let key7 = btable.keys[7];
|
|
|
- let encbucket7 = btable.encbuckets[7];
|
|
|
- let bucket7 = BridgeTable::decrypt_bucket(&key7, &encbucket7)?;
|
|
|
+ let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
|
|
|
println!("bucket 7 = {:?}", bucket7);
|
|
|
// Try to decrypt a 3-bridge bucket
|
|
|
let key24 = btable.keys[24];
|
|
|
- let encbucket24 = btable.encbuckets[24];
|
|
|
- let bucket24 = BridgeTable::decrypt_bucket(&key24, &encbucket24)?;
|
|
|
+ let bucket24 = btable.decrypt_bucket_id(24, &key24)?;
|
|
|
println!("bucket 24 = {:?}", bucket24);
|
|
|
// Try to decrypt a bucket with the wrong key
|
|
|
let key12 = btable.keys[12];
|
|
|
- let encbucket15 = btable.encbuckets[15];
|
|
|
- let res = BridgeTable::decrypt_bucket(&key12, &encbucket15).unwrap_err();
|
|
|
+ let res = btable.decrypt_bucket_id(15, &key12).unwrap_err();
|
|
|
println!("bucket key mismatch = {:?}", res);
|
|
|
Ok(())
|
|
|
}
|
|
@@ -252,3 +260,16 @@ pub fn to_scalar(id: u32, key: [u8; 16]) -> Scalar {
|
|
|
// This cannot fail, since we're only using the low 20 bytes of b
|
|
|
Scalar::from_canonical_bytes(b).unwrap()
|
|
|
}
|
|
|
+
|
|
|
+/// Convert a Scalar attribute to an id and key if possible
|
|
|
+pub fn from_scalar(s: Scalar) -> Result<(u32, [u8; 16]), aead::Error> {
|
|
|
+ // Check that the top 12 bytes of the Scalar are 0
|
|
|
+ let sbytes = s.as_bytes();
|
|
|
+ if sbytes[20..].ct_eq(&[0u8; 12]).unwrap_u8() == 0 {
|
|
|
+ return Err(aead::Error);
|
|
|
+ }
|
|
|
+ let id = u32::from_le_bytes(sbytes[16..20].try_into().unwrap());
|
|
|
+ let mut key: [u8; 16] = [0; 16];
|
|
|
+ key.copy_from_slice(&sbytes[..16]);
|
|
|
+ Ok((id, key))
|
|
|
+}
|