|
@@ -8,7 +8,9 @@ that the credentials contain the bucket attributes, which include both
|
|
|
the id and the bucket decrytpion key, but the table just contains the
|
|
|
bucket ids.) */
|
|
|
|
|
|
+use curve25519_dalek::ristretto::CompressedRistretto;
|
|
|
use curve25519_dalek::ristretto::RistrettoBasepointTable;
|
|
|
+use curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
use curve25519_dalek::scalar::Scalar;
|
|
|
|
|
|
use sha2::Digest;
|
|
@@ -21,6 +23,7 @@ use rand::RngCore;
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
use super::bridge_table;
|
|
|
+use super::cred::Migration;
|
|
|
use super::IssuerPrivKey;
|
|
|
use super::CMZ_B_TABLE;
|
|
|
|
|
@@ -168,3 +171,52 @@ impl MigrationTable {
|
|
|
.collect()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/// Decrypt an encrypted Migration credential given Qk, the known
|
|
|
+/// attributes id and from_bucket for the Migration credential, and a
|
|
|
+/// HashMap mapping labels to ciphertexts.
|
|
|
+pub fn decrypt_cred(
|
|
|
+ Qk: &RistrettoPoint,
|
|
|
+ lox_id: &Scalar,
|
|
|
+ from_bucket: &Scalar,
|
|
|
+ enc_migration_table: &HashMap<[u8; 16], [u8; ENC_MIGRATION_BYTES]>,
|
|
|
+) -> Option<Migration> {
|
|
|
+ // Compute the hash of (id, from_bucket, Qk)
|
|
|
+ let mut hasher = Sha256::new();
|
|
|
+ hasher.update(&lox_id.as_bytes()[..]);
|
|
|
+ hasher.update(&from_bucket.as_bytes()[..]);
|
|
|
+ hasher.update(&Qk.compress().as_bytes()[..]);
|
|
|
+ let fullhash = hasher.finalize();
|
|
|
+
|
|
|
+ // Use the first half of the above hash as the label
|
|
|
+ let mut label: [u8; 16] = [0; 16];
|
|
|
+ label[..].copy_from_slice(&fullhash[..16]);
|
|
|
+
|
|
|
+ // Look up the label in the HashMap
|
|
|
+ let ciphertext = enc_migration_table.get(&label)?;
|
|
|
+
|
|
|
+ // Create the decryption key from the 2nd half of the hash
|
|
|
+ let aeskey = GenericArray::from_slice(&fullhash[16..]);
|
|
|
+
|
|
|
+ // Decrypt
|
|
|
+ let nonce = GenericArray::from_slice(&ciphertext[..12]);
|
|
|
+ let cipher = Aes128Gcm::new(aeskey);
|
|
|
+ let plaintext: Vec<u8> = match cipher.decrypt(&nonce, ciphertext[12..].as_ref()) {
|
|
|
+ Ok(v) => v,
|
|
|
+ Err(_) => return None,
|
|
|
+ };
|
|
|
+ let plaintextbytes = plaintext.as_slice();
|
|
|
+ let mut to_bucket_bytes: [u8; 32] = [0; 32];
|
|
|
+ to_bucket_bytes.copy_from_slice(&plaintextbytes[..32]);
|
|
|
+ let to_bucket = Scalar::from_bytes_mod_order(to_bucket_bytes);
|
|
|
+ let P = CompressedRistretto::from_slice(&plaintextbytes[32..64]).decompress()?;
|
|
|
+ let Q = CompressedRistretto::from_slice(&plaintextbytes[64..]).decompress()?;
|
|
|
+
|
|
|
+ Some(Migration {
|
|
|
+ P,
|
|
|
+ Q,
|
|
|
+ lox_id: *lox_id,
|
|
|
+ from_bucket: *from_bucket,
|
|
|
+ to_bucket,
|
|
|
+ })
|
|
|
+}
|