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; * cred.P;
return Q == cred.Q; 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 /// 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 the id and the bucket decrytpion key, but the table just contains the
bucket ids.) */ bucket ids.) */
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::ristretto::RistrettoBasepointTable; use curve25519_dalek::ristretto::RistrettoBasepointTable;
use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use sha2::Digest; use sha2::Digest;
@ -21,6 +23,7 @@ use rand::RngCore;
use std::collections::HashMap; use std::collections::HashMap;
use super::bridge_table; use super::bridge_table;
use super::cred::Migration;
use super::IssuerPrivKey; use super::IssuerPrivKey;
use super::CMZ_B_TABLE; use super::CMZ_B_TABLE;
@ -168,3 +171,52 @@ impl MigrationTable {
.collect() .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); ba.advance_days(47);
let (promreq, promstate) = trust_promotion::request(&cred, &ba.lox_pub, ba.today()).unwrap(); let (promreq, promstate) = trust_promotion::request(&cred, &ba.lox_pub, ba.today()).unwrap();
let resp = ba.handle_trust_promotion(promreq).unwrap(); let promresp = ba.handle_trust_promotion(promreq).unwrap();
println!("resp = {:?}", resp); 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),
}
}