Skip to content

Commit

Permalink
Merge pull request theheraldproject#194 from adamfowleruk/feature-95
Browse files Browse the repository at this point in the history
Fixes theheraldproject#95. Clarifies security properties of SimplePayload
  • Loading branch information
adamfowleruk authored May 31, 2021
2 parents 6c084b9 + 36e89b8 commit c722c72
Showing 1 changed file with 61 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import java.text.SimpleDateFormat;
import java.util.Date;

/// Key generation functions
/**
* Key generation functions for the Simple Payload.
*/
public class K {
/// Secret key length
private final static int secretKeyLength = 2048;
Expand Down Expand Up @@ -77,66 +79,113 @@ public final static SecureRandom getSecureRandom() {
}
}

/// Generate matching keys K_{m}^{0...days}
/**
* Generate matching keys K_{m}^{0...days}
*
* @param secretKey The SecretKey to use to generate the sequence of daily MatchingKeys
* @return
*/
protected static MatchingKey[] matchingKeys(SecretKey secretKey) {
final int n = days;
/**
Forward secured matching key seeds are generated by a reversed hash chain with truncation, to ensure future keys cannot be derived from historic keys. The cryptographic hash function offers a one-way function for forward security. The truncation function offers additional assurance by deleting intermediate key material, thus a compromised hash function will still maintain forward security.
* Matching key seeds are generated by a reversed hash chain with truncation,
* to ensure future keys cannot be derived from historic keys. The cryptographic hash
* function offers a one-way function for this purpose.
*
* The truncation function offers additional assurance by deleting intermediate key
* material, thus a compromised hash function will still prevent future keys being
* derivced from current keys.
*
* Note: This implementation does NOT provide 'Perfect Forward Secrecy' because the
* SecretKey used is the same for all days. This means a compromise of the SecretKey in
* future would allow previous days' material to be decrypted.
*
* For those wishing to ensure Perfect Forward Secrecy, at least on a per-day basis,
* please use a different SecretKey
* per day. Note that because this places an extra communication and management burden
* on an end to end digital contact tracing (DCT) system, this is not the default
* implementation used in Herald.
*/
final MatchingKeySeed[] matchingKeySeed = new MatchingKeySeed[n + 1];
/**
The last matching key seed on day 2000 (over 5 years from epoch) is the hash of the secret key. A new secret key will need to be established before all matching key seeds are exhausted on day 2000.
* The last matching key seed on day 2000 (over 5 years from epoch) is the hash of the
* secret key. A new secret key will need to be established before all matching key seeds
* are exhausted on day 2000.
*/
matchingKeySeed[n] = new MatchingKeySeed(F.hash(secretKey));
for (int i=n; i-->0;) {
matchingKeySeed[i] = new MatchingKeySeed(F.hash(F.truncate(matchingKeySeed[i + 1])));
}
/**
Matching key for day i is the hash of the matching key seed for day i xor i - 1. A separation of matching key from its seed is necessary because the matching key is distributed by the server to all phones for on-device matching in a decentralised contact tracing solution. Given a seed is used to derive the seeds for other days, publishing the hash prevents an attacker from establishing the other seeds.
* Matching key for day i is the hash of the matching key seed for day i xor i - 1.
* A separation of matching key from its seed is necessary because the matching key is
* distributed by the server to all phones for on-device matching in a decentralised
* digital contact tracing solution. Given a seed is used to derive the seeds for other
* days, publishing the hash prevents an attacker from establishing the other seeds.
*/
final MatchingKey[] matchingKey = new MatchingKey[n + 1];
for (int i=1; i<=n; i++) {
matchingKey[i] = new MatchingKey(F.hash(F.xor(matchingKeySeed[i], matchingKeySeed[i - 1])));
}
/**
Matching key on day 0 is derived from matching key seed on day 0 and day -1. Implemented as special case for clarity in above code.
* Matching key on day 0 is derived from matching key seed on day 0 and day -1.
* Implemented as special case for clarity in above code.
*/
final MatchingKeySeed matchingKeySeedMinusOne = new MatchingKeySeed(F.hash(F.truncate(matchingKeySeed[0])));
matchingKey[0] = new MatchingKey(F.hash(F.xor(matchingKeySeed[0], matchingKeySeedMinusOne)));
return matchingKey;
}

/// Generate contact keys K_{c}^{0...periods}
/**
* Generate contact keys K_{c}^{0...periods}
*
* @param matchingKey The daily MatchingKey to use to generate a set of period ContactKeys
* @return The ContactKey set generated from the MatchingKey
*/
protected static ContactKey[] contactKeys(MatchingKey matchingKey) {
final int n = periods;

/**
Forward secured contact key seeds are generated by a reversed hash chain with truncation, to ensure future keys cannot be derived from historic keys. This is identical to the procedure for generating the matching key seeds. The seeds are never transmitted from the phone. They are cryptographically challenging to reveal from the broadcasted contact keys, while easy to generate given the matching key, or secret key.
* Contact key seeds are generated by a reversed hash chain with truncation, to ensure
* future keys cannot be derived from historic keys. This is identical to the procedure
* for generating the matching key seeds. The seeds are never transmitted from the phone.
* They are cryptographically challenging to reveal from the broadcasted contact keys,
* while easy to generate given the matching key, or secret key.
*/
final ContactKeySeed[] contactKeySeed = new ContactKeySeed[n + 1];
/**
The last contact key seed on day i at period 240 (last 6 minutes of the day) is the hash of the matching key for day i.
* The last contact key seed on day i at period 240 (last 6 minutes of the day) is the
* hash of the matching key for day i.
*/
contactKeySeed[n] = new ContactKeySeed(F.hash(matchingKey));
for (int j=n; j-->0;) {
contactKeySeed[j] = new ContactKeySeed(F.hash(F.truncate(contactKeySeed[j + 1])));
}
/**
Contact key for day i at period j is the hash of the contact key seed for day i at period j xor j - 1. A separation of contact key from its seed is necessary because the contact key is distributed to other phones as evidence for encounters on day i within period j. Given a seed is used to derive the seeds for other periods on the same day, transmitting the hash prevents an attacker from establishing the other seeds on day i.
* Contact key for day i at period j is the hash of the contact key seed for day i at
* period j xor j - 1. A separation of contact key from its seed is necessary because the
* contact key is distributed to other phones as evidence for encounters on day i within
* period j. Given a seed is used to derive the seeds for other periods on the same day,
* transmitting the hash prevents an attacker from establishing the other seeds on day i.
*/
final ContactKey[] contactKey = new ContactKey[n + 1];
for (int j=1; j<=n; j++) {
contactKey[j] = new ContactKey(F.hash(F.xor(contactKeySeed[j], contactKeySeed[j - 1])));
}
/**
Contact key on day 0 is derived from contact key seed at period 0 and period -1. Implemented as special case for clarity in above code.
* Contact key on day 0 is derived from contact key seed at period 0 and period -1.
* Implemented as special case for clarity in above code.
*/
final ContactKeySeed contactKeySeedMinusOne = new ContactKeySeed(F.hash(F.truncate(contactKeySeed[0])));
contactKey[0] = new ContactKey(F.hash(F.xor(contactKeySeed[0], contactKeySeedMinusOne)));
return contactKey;
}

/// Generate contact identifer I_{c}
/**
* Generate contact identifer I_{c}
*
* @param contactKey The ContactKey used to generate this period's ContactIdentifier
*/
protected static ContactIdentifier contactIdentifier(ContactKey contactKey) {
return new ContactIdentifier(F.truncate(contactKey, 16));
}
Expand Down

0 comments on commit c722c72

Please sign in to comment.