diff --git a/components/net/sf/briar/crypto/CryptoComponentImpl.java b/components/net/sf/briar/crypto/CryptoComponentImpl.java index c175fa7dfed751f551a0e54ce2bd73b62fac37eb..eb7cab4963164595884a4b529d1f9224260eae45 100644 --- a/components/net/sf/briar/crypto/CryptoComponentImpl.java +++ b/components/net/sf/briar/crypto/CryptoComponentImpl.java @@ -43,15 +43,15 @@ class CryptoComponentImpl implements CryptoComponent { private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding"; private static final String MAC_ALGO = "HMacSHA384"; - // Labels for key derivation, null-terminated - private static final byte[] TAG = { 'T', 'A', 'G', 0 }; - private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E', 0 }; - private static final byte[] MAC = { 'M', 'A', 'C', 0 }; - // Labels for secret derivation, null-terminated - private static final byte[] FIRST = { 'F', 'I', 'R', 'S', 'T', 0 }; - private static final byte[] NEXT = { 'N', 'E', 'X', 'T', 0 }; - // Label for confirmation code derivation, null-terminated - private static final byte[] CODE = { 'C', 'O', 'D', 'E', 0 }; + // Labels for key derivation + private static final byte[] TAG = { 'T', 'A', 'G' }; + private static final byte[] FRAME = { 'F', 'R', 'A', 'M', 'E' }; + private static final byte[] MAC = { 'M', 'A', 'C' }; + // Labels for secret derivation + private static final byte[] FIRST = { 'F', 'I', 'R', 'S', 'T' }; + private static final byte[] NEXT = { 'N', 'E', 'X', 'T' }; + // Label for confirmation code derivation + private static final byte[] CODE = { 'C', 'O', 'D', 'E' }; // Context strings for key and confirmation code derivation private static final byte[] INITIATOR = { 'I' }; private static final byte[] RESPONDER = { 'R' }; @@ -103,18 +103,14 @@ class CryptoComponentImpl implements CryptoComponent { // The secret must be usable as a key if(secret.length != SECRET_KEY_BYTES) 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 - if(label.length + context.length + 5 > KEY_DERIVATION_IV_BYTES) + if(label.length + context.length + 4 > KEY_DERIVATION_IV_BYTES) 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]; - System.arraycopy(label, 0, ivBytes, 0, label.length); - // Next comes the length-prefixed context - ByteUtils.writeUint32(context.length, ivBytes, label.length); + ByteUtils.writeUint8(label.length, ivBytes, 0); + System.arraycopy(label, 0, ivBytes, 2, label.length); + ByteUtils.writeUint8(context.length, ivBytes, label.length + 2); System.arraycopy(context, 0, ivBytes, label.length + 4, context.length); // Use the secret and the IV to encrypt a blank plaintext IvParameterSpec iv = new IvParameterSpec(ivBytes); @@ -138,8 +134,7 @@ class CryptoComponentImpl implements CryptoComponent { MessageDigest messageDigest = getMessageDigest(); byte[] ourHash = messageDigest.digest(ourPublicKey); byte[] theirHash = messageDigest.digest(theirPublicKey); - // The initiator and responder info for the concatenation KDF are - // the hashes of the corresponding public keys + // The initiator and responder info are hashes of the public keys byte[] initiatorInfo, responderInfo; if(initiator) { initiatorInfo = ourHash; @@ -148,8 +143,7 @@ class CryptoComponentImpl implements CryptoComponent { initiatorInfo = theirHash; responderInfo = ourHash; } - // The public info for the concatenation KDF is the invitation code - // as a uint32 + // The public info is the invitation code as a uint32 byte[] publicInfo = new byte[4]; ByteUtils.writeUint32(invitationCode, publicInfo, 0); // The raw secret comes from the key agreement algorithm @@ -183,23 +177,21 @@ class CryptoComponentImpl implements CryptoComponent { MessageDigest messageDigest = getMessageDigest(); if(messageDigest.getDigestLength() < SECRET_KEY_BYTES) throw new RuntimeException(); - // 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(); - // All other fields are length-prefixed + // All fields are length-prefixed byte[] length = new byte[4]; - ByteUtils.writeUint32(rawSecret.length, length, 0); + ByteUtils.writeUint8(rawSecret.length, length, 0); messageDigest.update(length); messageDigest.update(rawSecret); + ByteUtils.writeUint8(label.length, length, 0); + messageDigest.update(length); messageDigest.update(label); - ByteUtils.writeUint32(initiatorInfo.length, length, 0); + ByteUtils.writeUint8(initiatorInfo.length, length, 0); messageDigest.update(length); messageDigest.update(initiatorInfo); - ByteUtils.writeUint32(responderInfo.length, length, 0); + ByteUtils.writeUint8(responderInfo.length, length, 0); messageDigest.update(length); messageDigest.update(responderInfo); - ByteUtils.writeUint32(publicInfo.length, length, 0); + ByteUtils.writeUint8(publicInfo.length, length, 0); messageDigest.update(length); messageDigest.update(publicInfo); byte[] hash = messageDigest.digest(); diff --git a/util/net/sf/briar/util/ByteUtils.java b/util/net/sf/briar/util/ByteUtils.java index 1c3f9bdc13d1ebb419ad97531d876eb2c4017190..e19c7e3ca39ce68393b7e6a6bb24e9597ab3397a 100644 --- a/util/net/sf/briar/util/ByteUtils.java +++ b/util/net/sf/briar/util/ByteUtils.java @@ -12,10 +12,17 @@ public class ByteUtils { */ 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) { if(i < 0) 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 + 1] = (byte) (i & 0xFF); } @@ -23,7 +30,7 @@ public class ByteUtils { public static void writeUint32(long i, byte[] b, int offset) { if(i < 0L) 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 + 1] = (byte) (i >> 16 & 0xFF); b[offset + 2] = (byte) (i >> 8 & 0xFF);