Преглед на файлове

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

Ian Goldberg преди 3 години
родител
ревизия
2fa0937c46
променени са 4 файла, в които са добавени 92 реда и са изтрити 2 реда
  1. 11 0
      src/lib.rs
  2. 52 0
      src/migration_table.rs
  3. 9 2
      src/tests.rs
  4. 20 0
      src/trust_promotion.rs

+ 11 - 0
src/lib.rs

@@ -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

+ 52 - 0
src/migration_table.rs

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

+ 9 - 2
src/tests.rs

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

+ 20 - 0
src/trust_promotion.rs

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