Skip to content
Snippets Groups Projects
Commit d7581586 authored by akwizgran's avatar akwizgran
Browse files

Length prefix all KDF arguments.

parent 474fa3d5
No related branches found
No related tags found
No related merge requests found
...@@ -43,15 +43,15 @@ class CryptoComponentImpl implements CryptoComponent { ...@@ -43,15 +43,15 @@ class CryptoComponentImpl implements CryptoComponent {
private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding"; private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
private static final String MAC_ALGO = "HMacSHA384"; private static final String MAC_ALGO = "HMacSHA384";
// Labels for key derivation, null-terminated // Labels for key derivation
private static final byte[] TAG = { 'T', 'A', 'G', 0 }; private static final byte[] TAG = { 'T', 'A', 'G' };
private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E', 0 }; private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E' };
private static final byte[] MAC = { 'M', 'A', 'C', 0 }; private static final byte[] MAC = { 'M', 'A', 'C' };
// Labels for secret derivation, null-terminated // Labels for secret derivation
private static final byte[] FIRST = { 'F', 'I', 'R', 'S', 'T', 0 }; private static final byte[] FIRST = { 'F', 'I', 'R', 'S', 'T' };
private static final byte[] NEXT = { 'N', 'E', 'X', 'T', 0 }; private static final byte[] NEXT = { 'N', 'E', 'X', 'T' };
// Label for confirmation code derivation, null-terminated // Label for confirmation code derivation
private static final byte[] CODE = { 'C', 'O', 'D', 'E', 0 }; private static final byte[] CODE = { 'C', 'O', 'D', 'E' };
// Context strings for key and confirmation code derivation // Context strings for key and confirmation code derivation
private static final byte[] INITIATOR = { 'I' }; private static final byte[] INITIATOR = { 'I' };
private static final byte[] RESPONDER = { 'R' }; private static final byte[] RESPONDER = { 'R' };
...@@ -103,18 +103,14 @@ class CryptoComponentImpl implements CryptoComponent { ...@@ -103,18 +103,14 @@ class CryptoComponentImpl implements CryptoComponent {
// The secret must be usable as a key // The secret must be usable as a key
if(secret.length != SECRET_KEY_BYTES) if(secret.length != SECRET_KEY_BYTES)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
// The label string must be null-terminated
for(int i = 0; i < label.length - 1; i++)
if(label[i] == 0) throw new IllegalArgumentException();
if(label[label.length - 1] != 0) throw new IllegalArgumentException();
// The label and context must leave a byte free for the counter // The label and context must leave a byte free for the counter
if(label.length + context.length + 5 > KEY_DERIVATION_IV_BYTES) if(label.length + context.length + 4 > KEY_DERIVATION_IV_BYTES)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
// The IV starts with the null-terminated label // The IV contains the length-prefixed label and context
byte[] ivBytes = new byte[KEY_DERIVATION_IV_BYTES]; byte[] ivBytes = new byte[KEY_DERIVATION_IV_BYTES];
System.arraycopy(label, 0, ivBytes, 0, label.length); ByteUtils.writeUint8(label.length, ivBytes, 0);
// Next comes the length-prefixed context System.arraycopy(label, 0, ivBytes, 2, label.length);
ByteUtils.writeUint32(context.length, ivBytes, label.length); ByteUtils.writeUint8(context.length, ivBytes, label.length + 2);
System.arraycopy(context, 0, ivBytes, label.length + 4, context.length); System.arraycopy(context, 0, ivBytes, label.length + 4, context.length);
// Use the secret and the IV to encrypt a blank plaintext // Use the secret and the IV to encrypt a blank plaintext
IvParameterSpec iv = new IvParameterSpec(ivBytes); IvParameterSpec iv = new IvParameterSpec(ivBytes);
...@@ -138,8 +134,7 @@ class CryptoComponentImpl implements CryptoComponent { ...@@ -138,8 +134,7 @@ class CryptoComponentImpl implements CryptoComponent {
MessageDigest messageDigest = getMessageDigest(); MessageDigest messageDigest = getMessageDigest();
byte[] ourHash = messageDigest.digest(ourPublicKey); byte[] ourHash = messageDigest.digest(ourPublicKey);
byte[] theirHash = messageDigest.digest(theirPublicKey); byte[] theirHash = messageDigest.digest(theirPublicKey);
// The initiator and responder info for the concatenation KDF are // The initiator and responder info are hashes of the public keys
// the hashes of the corresponding public keys
byte[] initiatorInfo, responderInfo; byte[] initiatorInfo, responderInfo;
if(initiator) { if(initiator) {
initiatorInfo = ourHash; initiatorInfo = ourHash;
...@@ -148,8 +143,7 @@ class CryptoComponentImpl implements CryptoComponent { ...@@ -148,8 +143,7 @@ class CryptoComponentImpl implements CryptoComponent {
initiatorInfo = theirHash; initiatorInfo = theirHash;
responderInfo = ourHash; responderInfo = ourHash;
} }
// The public info for the concatenation KDF is the invitation code // The public info is the invitation code as a uint32
// as a uint32
byte[] publicInfo = new byte[4]; byte[] publicInfo = new byte[4];
ByteUtils.writeUint32(invitationCode, publicInfo, 0); ByteUtils.writeUint32(invitationCode, publicInfo, 0);
// The raw secret comes from the key agreement algorithm // The raw secret comes from the key agreement algorithm
...@@ -183,23 +177,21 @@ class CryptoComponentImpl implements CryptoComponent { ...@@ -183,23 +177,21 @@ class CryptoComponentImpl implements CryptoComponent {
MessageDigest messageDigest = getMessageDigest(); MessageDigest messageDigest = getMessageDigest();
if(messageDigest.getDigestLength() < SECRET_KEY_BYTES) if(messageDigest.getDigestLength() < SECRET_KEY_BYTES)
throw new RuntimeException(); throw new RuntimeException();
// The label string must be null-terminated // All fields are length-prefixed
for(int i = 0; i < label.length - 1; i++)
if(label[i] == 0) throw new IllegalArgumentException();
if(label[label.length - 1] != 0) throw new IllegalArgumentException();
// All other fields are length-prefixed
byte[] length = new byte[4]; byte[] length = new byte[4];
ByteUtils.writeUint32(rawSecret.length, length, 0); ByteUtils.writeUint8(rawSecret.length, length, 0);
messageDigest.update(length); messageDigest.update(length);
messageDigest.update(rawSecret); messageDigest.update(rawSecret);
ByteUtils.writeUint8(label.length, length, 0);
messageDigest.update(length);
messageDigest.update(label); messageDigest.update(label);
ByteUtils.writeUint32(initiatorInfo.length, length, 0); ByteUtils.writeUint8(initiatorInfo.length, length, 0);
messageDigest.update(length); messageDigest.update(length);
messageDigest.update(initiatorInfo); messageDigest.update(initiatorInfo);
ByteUtils.writeUint32(responderInfo.length, length, 0); ByteUtils.writeUint8(responderInfo.length, length, 0);
messageDigest.update(length); messageDigest.update(length);
messageDigest.update(responderInfo); messageDigest.update(responderInfo);
ByteUtils.writeUint32(publicInfo.length, length, 0); ByteUtils.writeUint8(publicInfo.length, length, 0);
messageDigest.update(length); messageDigest.update(length);
messageDigest.update(publicInfo); messageDigest.update(publicInfo);
byte[] hash = messageDigest.digest(); byte[] hash = messageDigest.digest();
......
...@@ -12,10 +12,17 @@ public class ByteUtils { ...@@ -12,10 +12,17 @@ public class ByteUtils {
*/ */
public static final long MAX_32_BIT_UNSIGNED = 4294967295L; // 2^32 - 1 public static final long MAX_32_BIT_UNSIGNED = 4294967295L; // 2^32 - 1
public static void writeUint8(int i, byte[] b, int offset) {
if(i < 0) throw new IllegalArgumentException();
if(i > 255) throw new IllegalArgumentException();
if(b.length < offset) throw new IllegalArgumentException();
b[offset] = (byte) i;
}
public static void writeUint16(int i, byte[] b, int offset) { public static void writeUint16(int i, byte[] b, int offset) {
if(i < 0) throw new IllegalArgumentException(); if(i < 0) throw new IllegalArgumentException();
if(i > MAX_16_BIT_UNSIGNED) throw new IllegalArgumentException(); if(i > MAX_16_BIT_UNSIGNED) throw new IllegalArgumentException();
assert b.length >= offset + 2; if(b.length < offset + 2) throw new IllegalArgumentException();
b[offset] = (byte) (i >> 8); b[offset] = (byte) (i >> 8);
b[offset + 1] = (byte) (i & 0xFF); b[offset + 1] = (byte) (i & 0xFF);
} }
...@@ -23,7 +30,7 @@ public class ByteUtils { ...@@ -23,7 +30,7 @@ public class ByteUtils {
public static void writeUint32(long i, byte[] b, int offset) { public static void writeUint32(long i, byte[] b, int offset) {
if(i < 0L) throw new IllegalArgumentException(); if(i < 0L) throw new IllegalArgumentException();
if(i > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException(); if(i > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException();
assert b.length >= offset + 4; if(b.length < offset + 4) throw new IllegalArgumentException();
b[offset] = (byte) (i >> 24); b[offset] = (byte) (i >> 24);
b[offset + 1] = (byte) (i >> 16 & 0xFF); b[offset + 1] = (byte) (i >> 16 & 0xFF);
b[offset + 2] = (byte) (i >> 8 & 0xFF); b[offset + 2] = (byte) (i >> 8 & 0xFF);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment