Create Bucket Reachability credentials and put them in buckets as appropriate
This commit is contained in:
parent
33f3de3b68
commit
ba13545b3c
|
@ -8,11 +8,17 @@ buckets. Users will either download the whole encrypted bucket list or
|
||||||
use PIR to download a piece of it, so that the bridge authority does not
|
use PIR to download a piece of it, so that the bridge authority does not
|
||||||
learn which bucket the user has access to. */
|
learn which bucket the user has access to. */
|
||||||
|
|
||||||
|
use super::cred;
|
||||||
|
use super::IssuerPrivKey;
|
||||||
|
use super::CMZ_B_TABLE;
|
||||||
use aes_gcm::aead;
|
use aes_gcm::aead;
|
||||||
use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead};
|
use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead};
|
||||||
use aes_gcm::Aes128Gcm;
|
use aes_gcm::Aes128Gcm;
|
||||||
|
use curve25519_dalek::ristretto::CompressedRistretto;
|
||||||
|
use curve25519_dalek::ristretto::RistrettoBasepointTable;
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
|
@ -22,14 +28,14 @@ pub const BRIDGE_BYTES: usize = 220;
|
||||||
/// The max number of bridges per bucket
|
/// The max number of bridges per bucket
|
||||||
pub const MAX_BRIDGES_PER_BUCKET: usize = 3;
|
pub const MAX_BRIDGES_PER_BUCKET: usize = 3;
|
||||||
|
|
||||||
/// The size of a plaintext bucket
|
/// The minimum number of bridges in a bucket that must be reachable for
|
||||||
pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET;
|
/// the bucket to get a Bucket Reachability credential that will allow
|
||||||
|
/// users of that bucket to gain trust levels (once they are already at
|
||||||
/// The size of an encrypted bucket
|
/// level 1)
|
||||||
pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
|
pub const MIN_BUCKET_REACHABILITY: usize = 2;
|
||||||
|
|
||||||
/// A bridge information line
|
/// A bridge information line
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
|
||||||
pub struct BridgeLine {
|
pub struct BridgeLine {
|
||||||
/// IPv4 or IPv6 address
|
/// IPv4 or IPv6 address
|
||||||
pub addr: [u8; 16],
|
pub addr: [u8; 16],
|
||||||
|
@ -40,6 +46,20 @@ pub struct BridgeLine {
|
||||||
pub info: [u8; BRIDGE_BYTES - 18],
|
pub info: [u8; BRIDGE_BYTES - 18],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A bucket contains MAX_BRIDGES_PER_BUCKET bridges plus the
|
||||||
|
/// information needed to construct a Bucket Reachability credential,
|
||||||
|
/// which is a 4-byte date, and a (P,Q) MAC
|
||||||
|
type Bucket = (
|
||||||
|
[BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
||||||
|
Option<cred::BucketReachability>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// The size of a plaintext bucket
|
||||||
|
pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET + 4 + 32 + 32;
|
||||||
|
|
||||||
|
/// The size of an encrypted bucket
|
||||||
|
pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
|
||||||
|
|
||||||
impl Default for BridgeLine {
|
impl Default for BridgeLine {
|
||||||
/// An "empty" BridgeLine is represented by all zeros
|
/// An "empty" BridgeLine is represented by all zeros
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -68,25 +88,79 @@ impl BridgeLine {
|
||||||
res.info.copy_from_slice(&data[18..]);
|
res.info.copy_from_slice(&data[18..]);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
/// Encode a bucket to a byte array
|
/// Encode a bucket to a byte array, including a Bucket Reachability
|
||||||
pub fn bucket_encode(bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> [u8; BUCKET_BYTES] {
|
/// credential if appropriate
|
||||||
|
pub fn bucket_encode(
|
||||||
|
bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
||||||
|
reachable: &HashSet<BridgeLine>,
|
||||||
|
today: u32,
|
||||||
|
bucket_attr: &Scalar,
|
||||||
|
reachability_priv: &IssuerPrivKey,
|
||||||
|
) -> [u8; BUCKET_BYTES] {
|
||||||
let mut res: [u8; BUCKET_BYTES] = [0; BUCKET_BYTES];
|
let mut res: [u8; BUCKET_BYTES] = [0; BUCKET_BYTES];
|
||||||
let mut pos: usize = 0;
|
let mut pos: usize = 0;
|
||||||
|
let mut num_reachable: usize = 0;
|
||||||
for bridge in bucket {
|
for bridge in bucket {
|
||||||
res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
|
res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
|
||||||
|
if reachable.contains(bridge) {
|
||||||
|
num_reachable += 1;
|
||||||
|
}
|
||||||
pos += BRIDGE_BYTES;
|
pos += BRIDGE_BYTES;
|
||||||
}
|
}
|
||||||
|
if num_reachable >= MIN_BUCKET_REACHABILITY {
|
||||||
|
// Construct a Bucket Reachability credential for this
|
||||||
|
// bucket and today's date
|
||||||
|
let today_attr: Scalar = today.into();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
|
||||||
|
let b = Scalar::random(&mut rng);
|
||||||
|
let P = &b * Btable;
|
||||||
|
let Q = &(b
|
||||||
|
* (reachability_priv.x[0]
|
||||||
|
+ reachability_priv.x[1] * today_attr
|
||||||
|
+ reachability_priv.x[2] * bucket_attr))
|
||||||
|
* Btable;
|
||||||
|
res[pos..pos + 4].copy_from_slice(&today.to_le_bytes());
|
||||||
|
res[pos + 4..pos + 36].copy_from_slice(&P.compress().as_bytes()[..]);
|
||||||
|
res[pos + 36..].copy_from_slice(&Q.compress().as_bytes()[..]);
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
/// Decode a bucket from a byte array
|
/// Decode a bucket from a byte array, yielding the array of
|
||||||
pub fn bucket_decode(data: &[u8; BUCKET_BYTES]) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET] {
|
/// BridgeLine entries and an optional Bucket Reachability
|
||||||
|
/// credential
|
||||||
|
fn bucket_decode(data: &[u8; BUCKET_BYTES], bucket_attr: &Scalar) -> Bucket {
|
||||||
let mut pos: usize = 0;
|
let mut pos: usize = 0;
|
||||||
let mut res: [BridgeLine; MAX_BRIDGES_PER_BUCKET] = Default::default();
|
let mut bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET] = Default::default();
|
||||||
for bridge in res.iter_mut().take(MAX_BRIDGES_PER_BUCKET) {
|
for bridge in bridges.iter_mut().take(MAX_BRIDGES_PER_BUCKET) {
|
||||||
*bridge = BridgeLine::decode(data[pos..pos + BRIDGE_BYTES].try_into().unwrap());
|
*bridge = BridgeLine::decode(data[pos..pos + BRIDGE_BYTES].try_into().unwrap());
|
||||||
pos += BRIDGE_BYTES;
|
pos += BRIDGE_BYTES;
|
||||||
}
|
}
|
||||||
res
|
// See if there's a nonzero date in the Bucket Reachability
|
||||||
|
// Credential
|
||||||
|
let date = u32::from_le_bytes(data[pos..pos + 4].try_into().unwrap());
|
||||||
|
let (optP, optQ) = if date > 0 {
|
||||||
|
(
|
||||||
|
CompressedRistretto::from_slice(&data[pos + 4..pos + 36]).decompress(),
|
||||||
|
CompressedRistretto::from_slice(&data[pos + 36..]).decompress(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
if let (Some(P), Some(Q)) = (optP, optQ) {
|
||||||
|
let date_attr: Scalar = date.into();
|
||||||
|
(
|
||||||
|
bridges,
|
||||||
|
Some(cred::BucketReachability {
|
||||||
|
P,
|
||||||
|
Q,
|
||||||
|
date: date_attr,
|
||||||
|
bucket: *bucket_attr,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(bridges, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Create a random BridgeLine for testing
|
/// Create a random BridgeLine for testing
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -134,6 +208,12 @@ pub struct BridgeTable {
|
||||||
pub keys: Vec<[u8; 16]>,
|
pub keys: Vec<[u8; 16]>,
|
||||||
pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
|
pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
|
||||||
pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
|
pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
|
||||||
|
pub reachable: HashSet<BridgeLine>,
|
||||||
|
/// The date the buckets were last encrypted to make the encbucket.
|
||||||
|
///
|
||||||
|
/// The encbucket must be rebuilt each day so that the Bucket
|
||||||
|
/// Reachability credentials in the buckets can be refreshed.
|
||||||
|
pub date_last_enc: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invariant: the lengths of the keys and buckets vectors are the same.
|
// Invariant: the lengths of the keys and buckets vectors are the same.
|
||||||
|
@ -153,18 +233,35 @@ impl BridgeTable {
|
||||||
rng.fill_bytes(&mut key);
|
rng.fill_bytes(&mut key);
|
||||||
self.keys.push(key);
|
self.keys.push(key);
|
||||||
self.buckets.push(bucket);
|
self.buckets.push(bucket);
|
||||||
|
// Mark the new bridges as available
|
||||||
|
for b in bucket.iter() {
|
||||||
|
if b.port > 0 {
|
||||||
|
self.reachable.insert(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the vector of encrypted buckets from the keys and buckets
|
/// Create the vector of encrypted buckets from the keys and buckets
|
||||||
/// in the BridgeTable. All of the entries will be (randomly)
|
/// in the BridgeTable. All of the entries will be (randomly)
|
||||||
/// re-encrypted, so it will be hidden whether any individual bucket
|
/// re-encrypted, so it will be hidden whether any individual bucket
|
||||||
/// has changed (except for entirely new buckets, of course).
|
/// has changed (except for entirely new buckets, of course).
|
||||||
pub fn encrypt_table(&mut self) {
|
/// Bucket Reachability credentials are added to the buckets when
|
||||||
|
/// enough (at least MIN_BUCKET_REACHABILITY) bridges in the bucket
|
||||||
|
/// are reachable.
|
||||||
|
pub fn encrypt_table(&mut self, today: u32, reachability_priv: &IssuerPrivKey) {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
self.encbuckets.clear();
|
self.encbuckets.clear();
|
||||||
for (key, bucket) in self.keys.iter().zip(self.buckets.iter()) {
|
// We want id to be a u32, so we use .zip(0u32..) instead of
|
||||||
|
// enumerate()
|
||||||
|
for ((key, bucket), id) in self.keys.iter().zip(self.buckets.iter()).zip(0u32..) {
|
||||||
let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
|
let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
|
||||||
let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(bucket);
|
let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(
|
||||||
|
bucket,
|
||||||
|
&self.reachable,
|
||||||
|
today,
|
||||||
|
&to_scalar(id, key),
|
||||||
|
reachability_priv,
|
||||||
|
);
|
||||||
// Set the AES key
|
// Set the AES key
|
||||||
let aeskey = GenericArray::from_slice(key);
|
let aeskey = GenericArray::from_slice(key);
|
||||||
// Pick a random nonce
|
// Pick a random nonce
|
||||||
|
@ -178,13 +275,16 @@ impl BridgeTable {
|
||||||
encbucket[12..].copy_from_slice(ciphertext.as_slice());
|
encbucket[12..].copy_from_slice(ciphertext.as_slice());
|
||||||
self.encbuckets.push(encbucket);
|
self.encbuckets.push(encbucket);
|
||||||
}
|
}
|
||||||
|
self.date_last_enc = today;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt an individual encrypted bucket, given its key
|
/// Decrypt an individual encrypted bucket, given its id, key, and
|
||||||
|
/// the encrypted bucket itself
|
||||||
pub fn decrypt_bucket(
|
pub fn decrypt_bucket(
|
||||||
|
id: u32,
|
||||||
key: &[u8; 16],
|
key: &[u8; 16],
|
||||||
encbucket: &[u8; ENC_BUCKET_BYTES],
|
encbucket: &[u8; ENC_BUCKET_BYTES],
|
||||||
) -> Result<[BridgeLine; MAX_BRIDGES_PER_BUCKET], aead::Error> {
|
) -> Result<Bucket, aead::Error> {
|
||||||
// Set the nonce and the key
|
// Set the nonce and the key
|
||||||
let nonce = GenericArray::from_slice(&encbucket[0..12]);
|
let nonce = GenericArray::from_slice(&encbucket[0..12]);
|
||||||
let aeskey = GenericArray::from_slice(key);
|
let aeskey = GenericArray::from_slice(key);
|
||||||
|
@ -194,17 +294,14 @@ impl BridgeTable {
|
||||||
// Convert the plaintext bytes to an array of BridgeLines
|
// Convert the plaintext bytes to an array of BridgeLines
|
||||||
Ok(BridgeLine::bucket_decode(
|
Ok(BridgeLine::bucket_decode(
|
||||||
plaintext.as_slice().try_into().unwrap(),
|
plaintext.as_slice().try_into().unwrap(),
|
||||||
|
&to_scalar(id, key),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt an individual encrypted bucket, given its id and key
|
/// Decrypt an individual encrypted bucket, given its id and key
|
||||||
pub fn decrypt_bucket_id(
|
pub fn decrypt_bucket_id(&self, id: u32, key: &[u8; 16]) -> Result<Bucket, aead::Error> {
|
||||||
&self,
|
|
||||||
id: u32,
|
|
||||||
key: &[u8; 16],
|
|
||||||
) -> Result<[BridgeLine; MAX_BRIDGES_PER_BUCKET], aead::Error> {
|
|
||||||
let encbucket = self.encbuckets[id as usize];
|
let encbucket = self.encbuckets[id as usize];
|
||||||
BridgeTable::decrypt_bucket(key, &encbucket)
|
BridgeTable::decrypt_bucket(id, key, &encbucket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +313,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bridge_table() -> Result<(), aead::Error> {
|
fn test_bridge_table() -> Result<(), aead::Error> {
|
||||||
|
// Create private keys for the Bucket Reachability credentials
|
||||||
|
let reachability_priv = IssuerPrivKey::new(2);
|
||||||
// Create an empty bridge table
|
// Create an empty bridge table
|
||||||
let mut btable: BridgeTable = Default::default();
|
let mut btable: BridgeTable = Default::default();
|
||||||
// Make 20 buckets with one random bridge each
|
// Make 20 buckets with one random bridge each
|
||||||
|
@ -233,8 +332,13 @@ mod tests {
|
||||||
];
|
];
|
||||||
btable.new_bucket(bucket);
|
btable.new_bucket(bucket);
|
||||||
}
|
}
|
||||||
|
let today: u32 = time::OffsetDateTime::now_utc()
|
||||||
|
.date()
|
||||||
|
.julian_day()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
// Create the encrypted bridge table
|
// Create the encrypted bridge table
|
||||||
btable.encrypt_table();
|
btable.encrypt_table(today, &reachability_priv);
|
||||||
// Try to decrypt a 1-bridge bucket
|
// Try to decrypt a 1-bridge bucket
|
||||||
let key7 = btable.keys[7];
|
let key7 = btable.keys[7];
|
||||||
let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
|
let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
|
||||||
|
|
|
@ -7,9 +7,10 @@ zero-knowledge proof of its correctness (as it does at issuing time). */
|
||||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
/// A migration credential. This credential authorizes the holder of
|
/// A migration credential.
|
||||||
/// the Lox credential with the given id to switch from bucket
|
///
|
||||||
/// from_bucket to bucket to_bucket.
|
/// This credential authorizes the holder of the Lox credential with the
|
||||||
|
/// given id to switch from bucket from_bucket to bucket to_bucket.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Migration {
|
pub struct Migration {
|
||||||
pub P: RistrettoPoint,
|
pub P: RistrettoPoint,
|
||||||
|
@ -19,15 +20,17 @@ pub struct Migration {
|
||||||
pub to_bucket: Scalar,
|
pub to_bucket: Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main user credential in the Lox system. Its id is jointly
|
/// The main user credential in the Lox system.
|
||||||
/// generated by the user and the BA (bridge authority), but known only
|
///
|
||||||
/// to the user. The level_since date is the Julian date of when this
|
/// Its id is jointly generated by the user and the BA (bridge
|
||||||
/// user was changed to the current trust level. (P_noopmigration,
|
/// authority), but known only to the user. The level_since date is the
|
||||||
/// Q_noopmigration) are the MAC on the implicit no-op migration
|
/// Julian date of when this user was changed to the current trust
|
||||||
/// credential formed by the attributes (id, bucket, bucket), which
|
/// level. (P_noopmigration, Q_noopmigration) are the MAC on the
|
||||||
/// authorizes the user to switch from its current bucket to the same
|
/// implicit no-op migration credential formed by the attributes (id,
|
||||||
/// bucket (i.e., a no-op). This can be useful for hiding from the BA
|
/// bucket, bucket), which authorizes the user to switch from its
|
||||||
/// whether or not the user is performing a bucket migration.
|
/// current bucket to the same bucket (i.e., a no-op). This can be
|
||||||
|
/// useful for hiding from the BA whether or not the user is performing
|
||||||
|
/// a bucket migration.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Lox {
|
pub struct Lox {
|
||||||
pub P: RistrettoPoint,
|
pub P: RistrettoPoint,
|
||||||
|
@ -42,18 +45,40 @@ pub struct Lox {
|
||||||
pub Q_noopmigration: RistrettoPoint,
|
pub Q_noopmigration: RistrettoPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The migration key credential is never actually instantiated. It is
|
/// The migration key credential.
|
||||||
// an implicit credential with the following attributes:
|
///
|
||||||
// - lox_id: Scalar,
|
/// This credential is never actually instantiated. It is an implicit
|
||||||
// - from_bucket: Scalar
|
/// credential on attributes lox_id and from_bucket. This credential
|
||||||
// Plus the usual (P,Q) MAC. This credential type does have an
|
/// type does have an associated private and public key, however. The
|
||||||
// associated private and public key, however. The idea is that if a
|
/// idea is that if a user proves (in zero knowledge) that their Lox
|
||||||
// user proves (in zero knowledge) that their Lox credential entitles
|
/// credential entitles them to migrate from one bucket to another, the
|
||||||
// them to migrate from one bucket to another, the BA will issue a
|
/// BA will issue a (blinded, so the BA will not know the values of the
|
||||||
// (blinded, so the BA will not know the values of the attributes or of
|
/// attributes or of Q) MAC on this implicit credential. The Q value
|
||||||
// Q) MAC on this implicit credential. The Q value will then be used
|
/// will then be used (actually, a hash of lox_id, from_bucket, and Q)
|
||||||
// (actually, a hash of lox_id, from_bucket, and Q) to encrypt the
|
/// to encrypt the to_bucket, P, and Q fields of a Migration credential.
|
||||||
// to_bucket, P, and Q fields of a Migration credential. That way,
|
/// That way, people entitled to migrate buckets can receive a Migration
|
||||||
// people entitled to migrate buckets can receive a Migration credential
|
/// credential with their new bucket, without the BA learning either
|
||||||
// with their new bucket, without the BA learning either their old or
|
/// their old or new buckets.
|
||||||
// new buckets.
|
#[derive(Debug)]
|
||||||
|
pub struct MigrationKey {
|
||||||
|
pub P: RistrettoPoint,
|
||||||
|
pub Q: RistrettoPoint,
|
||||||
|
pub lox_id: Scalar,
|
||||||
|
pub from_bucket: Scalar,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Bucket Reachability credential.
|
||||||
|
///
|
||||||
|
/// Each day, a credential of this type is put in each bucket that has
|
||||||
|
/// at least a (configurable) threshold number of bridges that have not
|
||||||
|
/// been blocked as of the given date. Users can present this
|
||||||
|
/// credential (in zero knowledge) with today's date to prove that the
|
||||||
|
/// bridges in their bucket have not been blocked, in order to gain a
|
||||||
|
/// trust level.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BucketReachability {
|
||||||
|
pub P: RistrettoPoint,
|
||||||
|
pub Q: RistrettoPoint,
|
||||||
|
pub date: Scalar,
|
||||||
|
pub bucket: Scalar,
|
||||||
|
}
|
||||||
|
|
|
@ -186,6 +186,10 @@ pub struct BridgeAuth {
|
||||||
migrationkey_priv: IssuerPrivKey,
|
migrationkey_priv: IssuerPrivKey,
|
||||||
/// The public key for migration key credentials
|
/// The public key for migration key credentials
|
||||||
pub migrationkey_pub: IssuerPubKey,
|
pub migrationkey_pub: IssuerPubKey,
|
||||||
|
/// The private key for bucket reachability credentials
|
||||||
|
reachability_priv: IssuerPrivKey,
|
||||||
|
/// The public key for bucket reachability credentials
|
||||||
|
pub reachability_pub: IssuerPubKey,
|
||||||
|
|
||||||
/// The public key of the BridgeDb issuing open invitations
|
/// The public key of the BridgeDb issuing open invitations
|
||||||
pub bridgedb_pub: PublicKey,
|
pub bridgedb_pub: PublicKey,
|
||||||
|
@ -218,6 +222,8 @@ impl BridgeAuth {
|
||||||
let migration_pub = IssuerPubKey::new(&migration_priv);
|
let migration_pub = IssuerPubKey::new(&migration_priv);
|
||||||
let migrationkey_priv = IssuerPrivKey::new(2);
|
let migrationkey_priv = IssuerPrivKey::new(2);
|
||||||
let migrationkey_pub = IssuerPubKey::new(&migrationkey_priv);
|
let migrationkey_pub = IssuerPubKey::new(&migrationkey_priv);
|
||||||
|
let reachability_priv = IssuerPrivKey::new(2);
|
||||||
|
let reachability_pub = IssuerPubKey::new(&reachability_priv);
|
||||||
Self {
|
Self {
|
||||||
lox_priv,
|
lox_priv,
|
||||||
lox_pub,
|
lox_pub,
|
||||||
|
@ -225,6 +231,8 @@ impl BridgeAuth {
|
||||||
migration_pub,
|
migration_pub,
|
||||||
migrationkey_priv,
|
migrationkey_priv,
|
||||||
migrationkey_pub,
|
migrationkey_pub,
|
||||||
|
reachability_priv,
|
||||||
|
reachability_pub,
|
||||||
bridgedb_pub,
|
bridgedb_pub,
|
||||||
bridge_table: Default::default(),
|
bridge_table: Default::default(),
|
||||||
migration_table: Default::default(),
|
migration_table: Default::default(),
|
||||||
|
@ -258,6 +266,20 @@ impl BridgeAuth {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the encrypted bridge table.
|
||||||
|
///
|
||||||
|
/// Be sure to call this function when you want the latest version
|
||||||
|
/// of the table, since it will put fresh Bucket Reachability
|
||||||
|
/// credentials in the buckets each day.
|
||||||
|
pub fn enc_bridge_table(&mut self) -> &Vec<[u8; bridge_table::ENC_BUCKET_BYTES]> {
|
||||||
|
let today = self.today();
|
||||||
|
if self.bridge_table.date_last_enc != today {
|
||||||
|
self.bridge_table
|
||||||
|
.encrypt_table(today, &self.reachability_priv);
|
||||||
|
}
|
||||||
|
&self.bridge_table.encbuckets
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Verify the two MACs on a Lox credential
|
/// Verify the two MACs on a Lox credential
|
||||||
pub fn verify_lox(&self, cred: &cred::Lox) -> bool {
|
pub fn verify_lox(&self, cred: &cred::Lox) -> bool {
|
||||||
|
@ -297,6 +319,20 @@ impl BridgeAuth {
|
||||||
* cred.P;
|
* cred.P;
|
||||||
return Q == cred.Q;
|
return Q == cred.Q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
/// Verify the MAC on a Bucket Reachability credential
|
||||||
|
pub fn verify_reachability(&self, cred: &cred::BucketReachability) -> bool {
|
||||||
|
if cred.P.is_identity() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Q = (self.reachability_priv.x[0]
|
||||||
|
+ cred.date * self.reachability_priv.x[1]
|
||||||
|
+ cred.bucket * self.reachability_priv.x[2])
|
||||||
|
* cred.P;
|
||||||
|
return Q == cred.Q;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to extract a u64 from a Scalar
|
/// Try to extract a u64 from a Scalar
|
||||||
|
|
|
@ -28,7 +28,7 @@ fn test_open_invite() {
|
||||||
ba.bridge_table.new_bucket(bucket);
|
ba.bridge_table.new_bucket(bucket);
|
||||||
}
|
}
|
||||||
// Create the encrypted bridge table
|
// Create the encrypted bridge table
|
||||||
ba.bridge_table.encrypt_table();
|
ba.enc_bridge_table();
|
||||||
|
|
||||||
// Issue an open invitation
|
// Issue an open invitation
|
||||||
let inv = bdb.invite();
|
let inv = bdb.invite();
|
||||||
|
@ -40,7 +40,9 @@ fn test_open_invite() {
|
||||||
|
|
||||||
// Check that we can use the credential to read a bucket
|
// Check that we can use the credential to read a bucket
|
||||||
let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
|
let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
|
||||||
let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap();
|
let encbuckets = ba.enc_bridge_table();
|
||||||
|
let bucket =
|
||||||
|
bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
|
||||||
println!("cred = {:?}", cred);
|
println!("cred = {:?}", cred);
|
||||||
println!("bucket = {:?}", bucket);
|
println!("bucket = {:?}", bucket);
|
||||||
assert!(ba.verify_lox(&cred));
|
assert!(ba.verify_lox(&cred));
|
||||||
|
@ -74,7 +76,7 @@ fn setup() -> (BridgeDb, BridgeAuth) {
|
||||||
ba.migration_table.table.insert(3 * i + 2, 15 + i);
|
ba.migration_table.table.insert(3 * i + 2, 15 + i);
|
||||||
}
|
}
|
||||||
// Create the encrypted bridge table
|
// Create the encrypted bridge table
|
||||||
ba.bridge_table.encrypt_table();
|
ba.enc_bridge_table();
|
||||||
|
|
||||||
(bdb, ba)
|
(bdb, ba)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +111,9 @@ fn test_trust_promotion() {
|
||||||
// Check that we can use the to_bucket in the Migration credenital
|
// Check that we can use the to_bucket in the Migration credenital
|
||||||
// to read a bucket
|
// to read a bucket
|
||||||
let (id, key) = bridge_table::from_scalar(migcred.to_bucket).unwrap();
|
let (id, key) = bridge_table::from_scalar(migcred.to_bucket).unwrap();
|
||||||
let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap();
|
let encbuckets = ba.enc_bridge_table();
|
||||||
|
let bucket =
|
||||||
|
bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
|
||||||
println!("bucket = {:?}", bucket);
|
println!("bucket = {:?}", bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +132,8 @@ fn test_level0_migration() {
|
||||||
println!("newloxcred = {:?}", newloxcred);
|
println!("newloxcred = {:?}", newloxcred);
|
||||||
// Check that we can use the credenital to read a bucket
|
// Check that we can use the credenital to read a bucket
|
||||||
let (id, key) = bridge_table::from_scalar(newloxcred.bucket).unwrap();
|
let (id, key) = bridge_table::from_scalar(newloxcred.bucket).unwrap();
|
||||||
let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap();
|
let encbuckets = ba.enc_bridge_table();
|
||||||
|
let bucket =
|
||||||
|
bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
|
||||||
println!("bucket = {:?}", bucket);
|
println!("bucket = {:?}", bucket);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue