mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Code clarity, more unit tests for ByteUtils.
Addresses comments for !48.
This commit is contained in:
@@ -18,16 +18,19 @@ public interface TransportConstants {
|
|||||||
int STREAM_HEADER_LENGTH = STREAM_HEADER_IV_LENGTH + SecretKey.LENGTH
|
int STREAM_HEADER_LENGTH = STREAM_HEADER_IV_LENGTH + SecretKey.LENGTH
|
||||||
+ MAC_LENGTH;
|
+ MAC_LENGTH;
|
||||||
|
|
||||||
/** The length of the frame initalisation vector (IV) in bytes. */
|
/** The length of the frame nonce in bytes. */
|
||||||
int FRAME_IV_LENGTH = 24;
|
int FRAME_NONCE_LENGTH = 24;
|
||||||
|
|
||||||
/** The length of the frame header payload in bytes. */
|
/** The length of the plaintext frame header in bytes. */
|
||||||
int FRAME_HEADER_PAYLOAD_LENGTH = 4;
|
int FRAME_HEADER_PLAINTEXT_LENGTH = 4;
|
||||||
|
|
||||||
/** The length of the frame header in bytes. */
|
/** The length of the encrypted and authenticated frame header in bytes. */
|
||||||
int FRAME_HEADER_LENGTH = FRAME_HEADER_PAYLOAD_LENGTH + MAC_LENGTH;
|
int FRAME_HEADER_LENGTH = FRAME_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH;
|
||||||
|
|
||||||
/** The maximum length of a frame in bytes, including the header and MAC. */
|
/**
|
||||||
|
* The maximum length of an encrypted and authenticated frame in bytes,
|
||||||
|
* including the header.
|
||||||
|
*/
|
||||||
int MAX_FRAME_LENGTH = 1024;
|
int MAX_FRAME_LENGTH = 1024;
|
||||||
|
|
||||||
/** The maximum total length of the frame payload and padding in bytes. */
|
/** The maximum total length of the frame payload and padding in bytes. */
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static org.briarproject.api.invitation.InvitationConstants.CODE_BITS;
|
import static org.briarproject.api.invitation.InvitationConstants.CODE_BITS;
|
||||||
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS;
|
import static org.briarproject.crypto.EllipticCurveConstants.PARAMETERS;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_32_BYTES;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_64_BYTES;
|
||||||
import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
@@ -287,7 +289,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
||||||
byte[] period = new byte[8];
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
||||||
return new SecretKey(macKdf(k, ROTATE, period));
|
return new SecretKey(macKdf(k, ROTATE, period));
|
||||||
}
|
}
|
||||||
@@ -314,7 +316,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
int macLength = prf.getDigestSize();
|
int macLength = prf.getDigestSize();
|
||||||
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
||||||
// The input is the stream number as a 64-bit integer
|
// The input is the stream number as a 64-bit integer
|
||||||
byte[] input = new byte[8];
|
byte[] input = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(streamNumber, input, 0);
|
ByteUtils.writeUint64(streamNumber, input, 0);
|
||||||
prf.update(input, 0, input.length);
|
prf.update(input, 0, input.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
@@ -337,15 +339,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
byte[] iv = new byte[STORAGE_IV_BYTES];
|
byte[] iv = new byte[STORAGE_IV_BYTES];
|
||||||
secureRandom.nextBytes(iv);
|
secureRandom.nextBytes(iv);
|
||||||
// The output contains the salt, iterations, IV, ciphertext and MAC
|
// The output contains the salt, iterations, IV, ciphertext and MAC
|
||||||
int outputLen = salt.length + 4 + iv.length + input.length + macBytes;
|
int outputLen = salt.length + INT_32_BYTES + iv.length + input.length
|
||||||
|
+ macBytes;
|
||||||
byte[] output = new byte[outputLen];
|
byte[] output = new byte[outputLen];
|
||||||
System.arraycopy(salt, 0, output, 0, salt.length);
|
System.arraycopy(salt, 0, output, 0, salt.length);
|
||||||
ByteUtils.writeUint32(iterations, output, salt.length);
|
ByteUtils.writeUint32(iterations, output, salt.length);
|
||||||
System.arraycopy(iv, 0, output, salt.length + 4, iv.length);
|
System.arraycopy(iv, 0, output, salt.length + INT_32_BYTES, iv.length);
|
||||||
// Initialise the cipher and encrypt the plaintext
|
// Initialise the cipher and encrypt the plaintext
|
||||||
try {
|
try {
|
||||||
cipher.init(true, key, iv);
|
cipher.init(true, key, iv);
|
||||||
int outputOff = salt.length + 4 + iv.length;
|
int outputOff = salt.length + INT_32_BYTES + iv.length;
|
||||||
cipher.process(input, 0, input.length, output, outputOff);
|
cipher.process(input, 0, input.length, output, outputOff);
|
||||||
return output;
|
return output;
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
@@ -357,7 +360,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
AuthenticatedCipher cipher = new XSalsa20Poly1305AuthenticatedCipher();
|
||||||
int macBytes = cipher.getMacBytes();
|
int macBytes = cipher.getMacBytes();
|
||||||
// The input contains the salt, iterations, IV, ciphertext and MAC
|
// The input contains the salt, iterations, IV, ciphertext and MAC
|
||||||
if (input.length < PBKDF_SALT_BYTES + 4 + STORAGE_IV_BYTES + macBytes)
|
if (input.length < PBKDF_SALT_BYTES + INT_32_BYTES + STORAGE_IV_BYTES
|
||||||
|
+ macBytes)
|
||||||
return null; // Invalid input
|
return null; // Invalid input
|
||||||
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
||||||
System.arraycopy(input, 0, salt, 0, salt.length);
|
System.arraycopy(input, 0, salt, 0, salt.length);
|
||||||
@@ -365,7 +369,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
if (iterations < 0 || iterations > Integer.MAX_VALUE)
|
if (iterations < 0 || iterations > Integer.MAX_VALUE)
|
||||||
return null; // Invalid iteration count
|
return null; // Invalid iteration count
|
||||||
byte[] iv = new byte[STORAGE_IV_BYTES];
|
byte[] iv = new byte[STORAGE_IV_BYTES];
|
||||||
System.arraycopy(input, salt.length + 4, iv, 0, iv.length);
|
System.arraycopy(input, salt.length + INT_32_BYTES, iv, 0, iv.length);
|
||||||
// Derive the key from the password
|
// Derive the key from the password
|
||||||
SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations));
|
SecretKey key = new SecretKey(pbkdf2(password, salt, (int) iterations));
|
||||||
// Initialise the cipher
|
// Initialise the cipher
|
||||||
@@ -376,7 +380,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
// Try to decrypt the ciphertext (may be invalid)
|
// Try to decrypt the ciphertext (may be invalid)
|
||||||
try {
|
try {
|
||||||
int inputOff = salt.length + 4 + iv.length;
|
int inputOff = salt.length + INT_32_BYTES + iv.length;
|
||||||
int inputLen = input.length - inputOff;
|
int inputLen = input.length - inputOff;
|
||||||
byte[] output = new byte[inputLen - macBytes];
|
byte[] output = new byte[inputLen - macBytes];
|
||||||
cipher.process(input, inputOff, inputLen, output, 0);
|
cipher.process(input, inputOff, inputLen, output, 0);
|
||||||
@@ -394,7 +398,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
int hashLength = digest.getDigestSize();
|
int hashLength = digest.getDigestSize();
|
||||||
if (hashLength < SecretKey.LENGTH) throw new IllegalStateException();
|
if (hashLength < SecretKey.LENGTH) throw new IllegalStateException();
|
||||||
// Calculate the hash over the concatenated length-prefixed inputs
|
// Calculate the hash over the concatenated length-prefixed inputs
|
||||||
byte[] length = new byte[4];
|
byte[] length = new byte[INT_32_BYTES];
|
||||||
for (byte[] input : inputs) {
|
for (byte[] input : inputs) {
|
||||||
ByteUtils.writeUint32(input.length, length, 0);
|
ByteUtils.writeUint32(input.length, length, 0);
|
||||||
digest.update(length, 0, length.length);
|
digest.update(length, 0, length.length);
|
||||||
@@ -418,7 +422,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
int macLength = prf.getDigestSize();
|
int macLength = prf.getDigestSize();
|
||||||
if (macLength < SecretKey.LENGTH) throw new IllegalStateException();
|
if (macLength < SecretKey.LENGTH) throw new IllegalStateException();
|
||||||
// Calculate the PRF over the concatenated length-prefixed inputs
|
// Calculate the PRF over the concatenated length-prefixed inputs
|
||||||
byte[] length = new byte[4];
|
byte[] length = new byte[INT_32_BYTES];
|
||||||
for (byte[] input : inputs) {
|
for (byte[] input : inputs) {
|
||||||
ByteUtils.writeUint32(input.length, length, 0);
|
ByteUtils.writeUint32(input.length, length, 0);
|
||||||
prf.update(length, 0, length.length);
|
prf.update(length, 0, length.length);
|
||||||
|
|||||||
@@ -2,48 +2,51 @@ package org.briarproject.crypto;
|
|||||||
|
|
||||||
import org.briarproject.util.ByteUtils;
|
import org.briarproject.util.ByteUtils;
|
||||||
|
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_IV_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_16_BYTES;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_64_BYTES;
|
||||||
|
|
||||||
class FrameEncoder {
|
class FrameEncoder {
|
||||||
|
|
||||||
static void encodeIv(byte[] iv, long frameNumber, boolean header) {
|
static void encodeNonce(byte[] dest, long frameNumber, boolean header) {
|
||||||
if (iv.length < FRAME_IV_LENGTH) throw new IllegalArgumentException();
|
if (dest.length < FRAME_NONCE_LENGTH)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
if (frameNumber < 0) throw new IllegalArgumentException();
|
if (frameNumber < 0) throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint64(frameNumber, iv, 0);
|
ByteUtils.writeUint64(frameNumber, dest, 0);
|
||||||
if (header) iv[0] |= 0x80;
|
if (header) dest[0] |= 0x80;
|
||||||
for (int i = 8; i < FRAME_IV_LENGTH; i++) iv[i] = 0;
|
for (int i = INT_64_BYTES; i < FRAME_NONCE_LENGTH; i++) dest[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encodeHeader(byte[] header, boolean finalFrame,
|
static void encodeHeader(byte[] dest, boolean finalFrame,
|
||||||
int payloadLength, int paddingLength) {
|
int payloadLength, int paddingLength) {
|
||||||
if (header.length < FRAME_HEADER_PAYLOAD_LENGTH)
|
if (dest.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if (payloadLength < 0) throw new IllegalArgumentException();
|
if (payloadLength < 0) throw new IllegalArgumentException();
|
||||||
if (paddingLength < 0) throw new IllegalArgumentException();
|
if (paddingLength < 0) throw new IllegalArgumentException();
|
||||||
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
ByteUtils.writeUint16(payloadLength, header, 0);
|
ByteUtils.writeUint16(payloadLength, dest, 0);
|
||||||
ByteUtils.writeUint16(paddingLength, header, 2);
|
ByteUtils.writeUint16(paddingLength, dest, INT_16_BYTES);
|
||||||
if (finalFrame) header[0] |= 0x80;
|
if (finalFrame) dest[0] |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isFinalFrame(byte[] header) {
|
static boolean isFinalFrame(byte[] header) {
|
||||||
if (header.length < FRAME_HEADER_PAYLOAD_LENGTH)
|
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return (header[0] & 0x80) == 0x80;
|
return (header[0] & 0x80) == 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPayloadLength(byte[] header) {
|
static int getPayloadLength(byte[] header) {
|
||||||
if (header.length < FRAME_HEADER_PAYLOAD_LENGTH)
|
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, 0) & 0x7FFF;
|
return ByteUtils.readUint16(header, 0) & 0x7FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPaddingLength(byte[] header) {
|
static int getPaddingLength(byte[] header) {
|
||||||
if (header.length < FRAME_HEADER_PAYLOAD_LENGTH)
|
if (header.length < FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
return ByteUtils.readUint16(header, 2);
|
return ByteUtils.readUint16(header, INT_16_BYTES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,16 @@ package org.briarproject.crypto;
|
|||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
import org.briarproject.util.ByteUtils;
|
import org.briarproject.util.ByteUtils;
|
||||||
|
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_32_BYTES;
|
||||||
|
|
||||||
class PseudoRandomImpl implements PseudoRandom {
|
class PseudoRandomImpl implements PseudoRandom {
|
||||||
|
|
||||||
private final FortunaGenerator generator;
|
private final FortunaGenerator generator;
|
||||||
|
|
||||||
PseudoRandomImpl(int seed1, int seed2) {
|
PseudoRandomImpl(int seed1, int seed2) {
|
||||||
byte[] seed = new byte[8];
|
byte[] seed = new byte[INT_32_BYTES * 2];
|
||||||
ByteUtils.writeUint32(seed1, seed, 0);
|
ByteUtils.writeUint32(seed1, seed, 0);
|
||||||
ByteUtils.writeUint32(seed2, seed, 4);
|
ByteUtils.writeUint32(seed2, seed, INT_32_BYTES);
|
||||||
generator = new FortunaGenerator(seed);
|
generator = new FortunaGenerator(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import java.io.InputStream;
|
|||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_IV_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
@@ -23,7 +23,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey;
|
private final SecretKey streamHeaderKey;
|
||||||
private final byte[] frameIv, frameHeader, frameCiphertext;
|
private final byte[] frameNonce, frameHeader, frameCiphertext;
|
||||||
|
|
||||||
private SecretKey frameKey;
|
private SecretKey frameKey;
|
||||||
private long frameNumber;
|
private long frameNumber;
|
||||||
@@ -34,8 +34,8 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
this.in = in;
|
this.in = in;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
this.streamHeaderKey = streamHeaderKey;
|
this.streamHeaderKey = streamHeaderKey;
|
||||||
frameIv = new byte[FRAME_IV_LENGTH];
|
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
||||||
frameHeader = new byte[FRAME_HEADER_PAYLOAD_LENGTH];
|
frameHeader = new byte[FRAME_HEADER_PLAINTEXT_LENGTH];
|
||||||
frameCiphertext = new byte[MAX_FRAME_LENGTH];
|
frameCiphertext = new byte[MAX_FRAME_LENGTH];
|
||||||
frameKey = null;
|
frameKey = null;
|
||||||
frameNumber = 0;
|
frameNumber = 0;
|
||||||
@@ -60,12 +60,12 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// Decrypt and authenticate the frame header
|
// Decrypt and authenticate the frame header
|
||||||
FrameEncoder.encodeIv(frameIv, frameNumber, true);
|
FrameEncoder.encodeNonce(frameNonce, frameNumber, true);
|
||||||
try {
|
try {
|
||||||
cipher.init(false, frameKey, frameIv);
|
cipher.init(false, frameKey, frameNonce);
|
||||||
int decrypted = cipher.process(frameCiphertext, 0,
|
int decrypted = cipher.process(frameCiphertext, 0,
|
||||||
FRAME_HEADER_LENGTH, frameHeader, 0);
|
FRAME_HEADER_LENGTH, frameHeader, 0);
|
||||||
if (decrypted != FRAME_HEADER_PAYLOAD_LENGTH)
|
if (decrypted != FRAME_HEADER_PLAINTEXT_LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
@@ -85,9 +85,9 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// Decrypt and authenticate the payload and padding
|
// Decrypt and authenticate the payload and padding
|
||||||
FrameEncoder.encodeIv(frameIv, frameNumber, false);
|
FrameEncoder.encodeNonce(frameNonce, frameNumber, false);
|
||||||
try {
|
try {
|
||||||
cipher.init(false, frameKey, frameIv);
|
cipher.init(false, frameKey, frameNonce);
|
||||||
int decrypted = cipher.process(frameCiphertext, FRAME_HEADER_LENGTH,
|
int decrypted = cipher.process(frameCiphertext, FRAME_HEADER_LENGTH,
|
||||||
payloadLength + paddingLength + MAC_LENGTH, payload, 0);
|
payloadLength + paddingLength + MAC_LENGTH, payload, 0);
|
||||||
if (decrypted != payloadLength + paddingLength)
|
if (decrypted != payloadLength + paddingLength)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import java.io.OutputStream;
|
|||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_PLAINTEXT_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_IV_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_NONCE_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
@@ -22,7 +22,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey, frameKey;
|
private final SecretKey streamHeaderKey, frameKey;
|
||||||
private final byte[] tag, streamHeaderIv;
|
private final byte[] tag, streamHeaderIv;
|
||||||
private final byte[] frameIv, frameHeader, framePlaintext, frameCiphertext;
|
private final byte[] frameNonce, frameHeader, framePlaintext, frameCiphertext;
|
||||||
|
|
||||||
private long frameNumber;
|
private long frameNumber;
|
||||||
private boolean writeTag, writeStreamHeader;
|
private boolean writeTag, writeStreamHeader;
|
||||||
@@ -36,8 +36,8 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
this.streamHeaderIv = streamHeaderIv;
|
this.streamHeaderIv = streamHeaderIv;
|
||||||
this.streamHeaderKey = streamHeaderKey;
|
this.streamHeaderKey = streamHeaderKey;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
frameIv = new byte[FRAME_IV_LENGTH];
|
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
||||||
frameHeader = new byte[FRAME_HEADER_PAYLOAD_LENGTH];
|
frameHeader = new byte[FRAME_HEADER_PLAINTEXT_LENGTH];
|
||||||
framePlaintext = new byte[MAX_PAYLOAD_LENGTH];
|
framePlaintext = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
frameCiphertext = new byte[MAX_FRAME_LENGTH];
|
frameCiphertext = new byte[MAX_FRAME_LENGTH];
|
||||||
frameNumber = 0;
|
frameNumber = 0;
|
||||||
@@ -59,11 +59,11 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength,
|
FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength,
|
||||||
paddingLength);
|
paddingLength);
|
||||||
// Encrypt and authenticate the frame header
|
// Encrypt and authenticate the frame header
|
||||||
FrameEncoder.encodeIv(frameIv, frameNumber, true);
|
FrameEncoder.encodeNonce(frameNonce, frameNumber, true);
|
||||||
try {
|
try {
|
||||||
cipher.init(true, frameKey, frameIv);
|
cipher.init(true, frameKey, frameNonce);
|
||||||
int encrypted = cipher.process(frameHeader, 0,
|
int encrypted = cipher.process(frameHeader, 0,
|
||||||
FRAME_HEADER_PAYLOAD_LENGTH, frameCiphertext, 0);
|
FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0);
|
||||||
if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException();
|
if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException badCipher) {
|
} catch (GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
@@ -73,9 +73,9 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
for (int i = 0; i < paddingLength; i++)
|
for (int i = 0; i < paddingLength; i++)
|
||||||
framePlaintext[payloadLength + i] = 0;
|
framePlaintext[payloadLength + i] = 0;
|
||||||
// Encrypt and authenticate the payload and padding
|
// Encrypt and authenticate the payload and padding
|
||||||
FrameEncoder.encodeIv(frameIv, frameNumber, false);
|
FrameEncoder.encodeNonce(frameNonce, frameNumber, false);
|
||||||
try {
|
try {
|
||||||
cipher.init(true, frameKey, frameIv);
|
cipher.init(true, frameKey, frameNonce);
|
||||||
int encrypted = cipher.process(framePlaintext, 0,
|
int encrypted = cipher.process(framePlaintext, 0,
|
||||||
payloadLength + paddingLength, frameCiphertext,
|
payloadLength + paddingLength, frameCiphertext,
|
||||||
FRAME_HEADER_LENGTH);
|
FRAME_HEADER_LENGTH);
|
||||||
|
|||||||
@@ -12,63 +12,72 @@ 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) {
|
/** The number of bytes needed to encode a 16-bit integer. */
|
||||||
if (i < 0) throw new IllegalArgumentException();
|
public static final int INT_16_BYTES = 2;
|
||||||
if (i > 255) throw new IllegalArgumentException();
|
|
||||||
if (b.length < offset) throw new IllegalArgumentException();
|
/** The number of bytes needed to encode a 32-bit integer. */
|
||||||
b[offset] = (byte) i;
|
public static final int INT_32_BYTES = 4;
|
||||||
|
|
||||||
|
/** The number of bytes needed to encode a 64-bit integer. */
|
||||||
|
public static final int INT_64_BYTES = 8;
|
||||||
|
|
||||||
|
public static void writeUint16(int src, byte[] dest, int offset) {
|
||||||
|
if (src < 0) throw new IllegalArgumentException();
|
||||||
|
if (src > MAX_16_BIT_UNSIGNED) throw new IllegalArgumentException();
|
||||||
|
if (dest.length < offset + INT_16_BYTES)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
dest[offset] = (byte) (src >> 8);
|
||||||
|
dest[offset + 1] = (byte) (src & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeUint16(int i, byte[] b, int offset) {
|
public static void writeUint32(long src, byte[] dest, int offset) {
|
||||||
if (i < 0) throw new IllegalArgumentException();
|
if (src < 0) throw new IllegalArgumentException();
|
||||||
if (i > MAX_16_BIT_UNSIGNED) throw new IllegalArgumentException();
|
if (src > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException();
|
||||||
if (b.length < offset + 2) throw new IllegalArgumentException();
|
if (dest.length < offset + INT_32_BYTES)
|
||||||
b[offset] = (byte) (i >> 8);
|
throw new IllegalArgumentException();
|
||||||
b[offset + 1] = (byte) (i & 0xFF);
|
dest[offset] = (byte) (src >> 24);
|
||||||
|
dest[offset + 1] = (byte) (src >> 16 & 0xFF);
|
||||||
|
dest[offset + 2] = (byte) (src >> 8 & 0xFF);
|
||||||
|
dest[offset + 3] = (byte) (src & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeUint32(long i, byte[] b, int offset) {
|
public static void writeUint64(long src, byte[] dest, int offset) {
|
||||||
if (i < 0) throw new IllegalArgumentException();
|
if (src < 0) throw new IllegalArgumentException();
|
||||||
if (i > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException();
|
if (dest.length < offset + INT_64_BYTES)
|
||||||
if (b.length < offset + 4) throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
b[offset] = (byte) (i >> 24);
|
dest[offset] = (byte) (src >> 56);
|
||||||
b[offset + 1] = (byte) (i >> 16 & 0xFF);
|
dest[offset + 1] = (byte) (src >> 48 & 0xFF);
|
||||||
b[offset + 2] = (byte) (i >> 8 & 0xFF);
|
dest[offset + 2] = (byte) (src >> 40 & 0xFF);
|
||||||
b[offset + 3] = (byte) (i & 0xFF);
|
dest[offset + 3] = (byte) (src >> 32 & 0xFF);
|
||||||
|
dest[offset + 4] = (byte) (src >> 24 & 0xFF);
|
||||||
|
dest[offset + 5] = (byte) (src >> 16 & 0xFF);
|
||||||
|
dest[offset + 6] = (byte) (src >> 8 & 0xFF);
|
||||||
|
dest[offset + 7] = (byte) (src & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeUint64(long i, byte[] b, int offset) {
|
public static int readUint16(byte[] src, int offset) {
|
||||||
if (i < 0) throw new IllegalArgumentException();
|
if (src.length < offset + INT_16_BYTES)
|
||||||
if (b.length < offset + 8) throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
b[offset] = (byte) (i >> 56);
|
return ((src[offset] & 0xFF) << 8) | (src[offset + 1] & 0xFF);
|
||||||
b[offset + 1] = (byte) (i >> 48 & 0xFF);
|
|
||||||
b[offset + 2] = (byte) (i >> 40 & 0xFF);
|
|
||||||
b[offset + 3] = (byte) (i >> 32 & 0xFF);
|
|
||||||
b[offset + 4] = (byte) (i >> 24 & 0xFF);
|
|
||||||
b[offset + 5] = (byte) (i >> 16 & 0xFF);
|
|
||||||
b[offset + 6] = (byte) (i >> 8 & 0xFF);
|
|
||||||
b[offset + 7] = (byte) (i & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int readUint16(byte[] b, int offset) {
|
public static long readUint32(byte[] src, int offset) {
|
||||||
if (b.length < offset + 2) throw new IllegalArgumentException();
|
if (src.length < offset + INT_32_BYTES)
|
||||||
return ((b[offset] & 0xFF) << 8) | (b[offset + 1] & 0xFF);
|
throw new IllegalArgumentException();
|
||||||
|
return ((src[offset] & 0xFFL) << 24)
|
||||||
|
| ((src[offset + 1] & 0xFFL) << 16)
|
||||||
|
| ((src[offset + 2] & 0xFFL) << 8)
|
||||||
|
| (src[offset + 3] & 0xFFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long readUint32(byte[] b, int offset) {
|
public static int readUint(byte[] src, int bits) {
|
||||||
if (b.length < offset + 4) throw new IllegalArgumentException();
|
if (src.length << 3 < bits) throw new IllegalArgumentException();
|
||||||
return ((b[offset] & 0xFFL) << 24) | ((b[offset + 1] & 0xFFL) << 16)
|
int dest = 0;
|
||||||
| ((b[offset + 2] & 0xFFL) << 8) | (b[offset + 3] & 0xFFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readUint(byte[] b, int bits) {
|
|
||||||
if (b.length << 3 < bits) throw new IllegalArgumentException();
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < bits; i++) {
|
for (int i = 0; i < bits; i++) {
|
||||||
if ((b[i >> 3] & 128 >> (i & 7)) != 0) result |= 1 << bits - i - 1;
|
if ((src[i >> 3] & 128 >> (i & 7)) != 0) dest |= 1 << bits - i - 1;
|
||||||
}
|
}
|
||||||
assert result >= 0;
|
assert dest >= 0;
|
||||||
assert result < 1 << bits;
|
assert dest < 1 << bits;
|
||||||
return result;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LEN
|
|||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ public class StreamDecrypterImplTest extends BriarTestCase {
|
|||||||
// The payload length plus padding length is invalid
|
// The payload length plus padding length is invalid
|
||||||
int payloadLength = MAX_PAYLOAD_LENGTH - 1, paddingLength = 2;
|
int payloadLength = MAX_PAYLOAD_LENGTH - 1, paddingLength = 2;
|
||||||
ByteUtils.writeUint16(payloadLength, frameHeader, 0);
|
ByteUtils.writeUint16(payloadLength, frameHeader, 0);
|
||||||
ByteUtils.writeUint16(paddingLength, frameHeader, 2);
|
ByteUtils.writeUint16(paddingLength, frameHeader, INT_16_BYTES);
|
||||||
byte[] payload = new byte[payloadLength];
|
byte[] payload = new byte[payloadLength];
|
||||||
random.nextBytes(payload);
|
random.nextBytes(payload);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LEN
|
|||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_16_BYTES;
|
||||||
|
|
||||||
class TestStreamDecrypter implements StreamDecrypter {
|
class TestStreamDecrypter implements StreamDecrypter {
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ class TestStreamDecrypter implements StreamDecrypter {
|
|||||||
}
|
}
|
||||||
finalFrame = (frame[0] & 0x80) == 0x80;
|
finalFrame = (frame[0] & 0x80) == 0x80;
|
||||||
int payloadLength = ByteUtils.readUint16(frame, 0) & 0x7FFF;
|
int payloadLength = ByteUtils.readUint16(frame, 0) & 0x7FFF;
|
||||||
int paddingLength = ByteUtils.readUint16(frame, 2);
|
int paddingLength = ByteUtils.readUint16(frame, INT_16_BYTES);
|
||||||
int frameLength = FRAME_HEADER_LENGTH + payloadLength + paddingLength
|
int frameLength = FRAME_HEADER_LENGTH + payloadLength + paddingLength
|
||||||
+ MAC_LENGTH;
|
+ MAC_LENGTH;
|
||||||
while (offset < frameLength) {
|
while (offset < frameLength) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.io.OutputStream;
|
|||||||
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
|
import static org.briarproject.util.ByteUtils.INT_16_BYTES;
|
||||||
|
|
||||||
class TestStreamEncrypter implements StreamEncrypter {
|
class TestStreamEncrypter implements StreamEncrypter {
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ class TestStreamEncrypter implements StreamEncrypter {
|
|||||||
if (writeTagAndHeader) writeTagAndHeader();
|
if (writeTagAndHeader) writeTagAndHeader();
|
||||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
ByteUtils.writeUint16(payloadLength, frameHeader, 0);
|
ByteUtils.writeUint16(payloadLength, frameHeader, 0);
|
||||||
ByteUtils.writeUint16(paddingLength, frameHeader, 2);
|
ByteUtils.writeUint16(paddingLength, frameHeader, INT_16_BYTES);
|
||||||
if (finalFrame) frameHeader[0] |= 0x80;
|
if (finalFrame) frameHeader[0] |= 0x80;
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
out.write(payload, 0, payloadLength);
|
out.write(payload, 0, payloadLength);
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package org.briarproject.util;
|
|||||||
import org.briarproject.BriarTestCase;
|
import org.briarproject.BriarTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.briarproject.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class ByteUtilsTest extends BriarTestCase {
|
public class ByteUtilsTest extends BriarTestCase {
|
||||||
|
|
||||||
@@ -17,6 +20,22 @@ public class ByteUtilsTest extends BriarTestCase {
|
|||||||
assertEquals(65535, ByteUtils.readUint16(b, 1));
|
assertEquals(65535, ByteUtils.readUint16(b, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadUint16ValidatesArguments() {
|
||||||
|
try {
|
||||||
|
ByteUtils.readUint16(new byte[1], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.readUint16(new byte[2], 1);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadUint32() {
|
public void testReadUint32() {
|
||||||
byte[] b = StringUtils.fromHexString("0000000000");
|
byte[] b = StringUtils.fromHexString("0000000000");
|
||||||
@@ -27,6 +46,21 @@ public class ByteUtilsTest extends BriarTestCase {
|
|||||||
assertEquals(4294967295L, ByteUtils.readUint32(b, 1));
|
assertEquals(4294967295L, ByteUtils.readUint32(b, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadUint32ValidatesArguments() {
|
||||||
|
try {
|
||||||
|
ByteUtils.readUint32(new byte[3], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.readUint32(new byte[4], 1);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteUint16() {
|
public void testWriteUint16() {
|
||||||
@@ -37,10 +71,38 @@ public class ByteUtilsTest extends BriarTestCase {
|
|||||||
assertEquals("00000100", StringUtils.toHexString(b));
|
assertEquals("00000100", StringUtils.toHexString(b));
|
||||||
ByteUtils.writeUint16(Short.MAX_VALUE, b, 1);
|
ByteUtils.writeUint16(Short.MAX_VALUE, b, 1);
|
||||||
assertEquals("007FFF00", StringUtils.toHexString(b));
|
assertEquals("007FFF00", StringUtils.toHexString(b));
|
||||||
ByteUtils.writeUint16(ByteUtils.MAX_16_BIT_UNSIGNED, b, 1);
|
ByteUtils.writeUint16(MAX_16_BIT_UNSIGNED, b, 1);
|
||||||
assertEquals("00FFFF00", StringUtils.toHexString(b));
|
assertEquals("00FFFF00", StringUtils.toHexString(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteUint16ValidatesArguments() {
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint16(0, new byte[1], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint16(0, new byte[2], 1);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint16(-1, new byte[2], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint16(MAX_16_BIT_UNSIGNED + 1, new byte[2], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteUint32() {
|
public void testWriteUint32() {
|
||||||
byte[] b = new byte[6];
|
byte[] b = new byte[6];
|
||||||
@@ -50,10 +112,38 @@ public class ByteUtilsTest extends BriarTestCase {
|
|||||||
assertEquals("000000000100", StringUtils.toHexString(b));
|
assertEquals("000000000100", StringUtils.toHexString(b));
|
||||||
ByteUtils.writeUint32(Integer.MAX_VALUE, b, 1);
|
ByteUtils.writeUint32(Integer.MAX_VALUE, b, 1);
|
||||||
assertEquals("007FFFFFFF00", StringUtils.toHexString(b));
|
assertEquals("007FFFFFFF00", StringUtils.toHexString(b));
|
||||||
ByteUtils.writeUint32(ByteUtils.MAX_32_BIT_UNSIGNED, b, 1);
|
ByteUtils.writeUint32(MAX_32_BIT_UNSIGNED, b, 1);
|
||||||
assertEquals("00FFFFFFFF00", StringUtils.toHexString(b));
|
assertEquals("00FFFFFFFF00", StringUtils.toHexString(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteUint32ValidatesArguments() {
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint32(0, new byte[3], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint32(0, new byte[4], 1);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint32(-1, new byte[4], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint32(MAX_32_BIT_UNSIGNED + 1, new byte[4], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteUint64() {
|
public void testWriteUint64() {
|
||||||
byte[] b = new byte[10];
|
byte[] b = new byte[10];
|
||||||
@@ -65,6 +155,28 @@ public class ByteUtilsTest extends BriarTestCase {
|
|||||||
assertEquals("007FFFFFFFFFFFFFFF00", StringUtils.toHexString(b));
|
assertEquals("007FFFFFFFFFFFFFFF00", StringUtils.toHexString(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteUint64ValidatesArguments() {
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint64(0, new byte[7], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint64(0, new byte[8], 1);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteUtils.writeUint64(-1, new byte[8], 0);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadUint() {
|
public void testReadUint() {
|
||||||
byte[] b = new byte[1];
|
byte[] b = new byte[1];
|
||||||
|
|||||||
Reference in New Issue
Block a user