Przeglądaj źródła

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

Ian Goldberg 3 lat temu
rodzic
commit
2fa0937c46
4 zmienionych plików z 92 dodań i 2 usunięć
  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;
             * 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

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

+ 9 - 2
src/tests.rs

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