Handle the response of the trust promotion protocol to produce the Migration credential

This commit is contained in:
Ian Goldberg 2021-04-30 13:30:20 -04:00
parent 03de724a8c
commit 6013386f07
4 changed files with 92 additions and 2 deletions

View File

@ -269,6 +269,17 @@ impl BridgeAuth {
* cred.P;
return Q == cred.Q;
}
#[cfg(test)]
/// Verify the MAC on a Migration credential
pub fn verify_migration(&self, cred: &cred::Migration) -> bool {
let Q = (self.migration_priv.x[0]
+ cred.lox_id * self.migration_priv.x[1]
+ cred.from_bucket * self.migration_priv.x[2]
+ cred.to_bucket * self.migration_priv.x[3])
* cred.P;
return Q == cred.Q;
}
}
/// Try to extract a u64 from a Scalar

View File

@ -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,
})
}

View File

@ -89,6 +89,13 @@ fn test_trust_promotion() {
ba.advance_days(47);
let (promreq, promstate) = trust_promotion::request(&cred, &ba.lox_pub, ba.today()).unwrap();
let resp = ba.handle_trust_promotion(promreq).unwrap();
println!("resp = {:?}", resp);
let promresp = ba.handle_trust_promotion(promreq).unwrap();
let migcred = trust_promotion::handle_response(promstate, promresp).unwrap();
println!("resp = {:?}", migcred);
assert!(ba.verify_migration(&migcred));
// Check that we can use the to_bucket in the Migration credenital
// to read a bucket
let (id, key) = bridge_table::from_scalar(migcred.to_bucket).unwrap();
let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap();
println!("bucket = {:?}", bucket);
}

View File

@ -527,3 +527,23 @@ impl BridgeAuth {
})
}
}
/// Handle the response to the request, producing a Migration credential
/// if successful.
///
/// The Migration credential can then be used in the migration protocol
/// to actually upgrade to trust level 1.
pub fn handle_response(state: State, resp: Response) -> Result<cred::Migration, ProofError> {
if resp.Pk.is_identity() {
return Err(ProofError::VerificationFailure);
}
// Decrypt the MAC on the Migration Key credential
let Qk = resp.EncQk.1 - (state.d * resp.EncQk.0);
// Use Qk to locate and decrypt the Migration credential
match migration_table::decrypt_cred(&Qk, &state.id, &state.bucket, &resp.enc_migration_table) {
Some(m) => Ok(m),
None => Err(ProofError::VerificationFailure),
}
}