mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 04:39:54 +01:00
Include stream number in stream header nonce.
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
package org.briarproject.crypto;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.crypto.StreamDecrypter;
|
||||
import org.briarproject.api.crypto.StreamDecrypterFactory;
|
||||
import org.briarproject.api.transport.StreamContext;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
class StreamDecrypterFactoryImpl implements StreamDecrypterFactory {
|
||||
|
||||
private final Provider<AuthenticatedCipher> cipherProvider;
|
||||
@@ -19,14 +19,17 @@ class StreamDecrypterFactoryImpl implements StreamDecrypterFactory {
|
||||
this.cipherProvider = cipherProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamDecrypter createStreamDecrypter(InputStream in,
|
||||
StreamContext ctx) {
|
||||
AuthenticatedCipher cipher = cipherProvider.get();
|
||||
return new StreamDecrypterImpl(in, cipher, ctx.getHeaderKey());
|
||||
return new StreamDecrypterImpl(in, cipher, ctx.getStreamNumber(),
|
||||
ctx.getHeaderKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamDecrypter createInvitationStreamDecrypter(InputStream in,
|
||||
SecretKey headerKey) {
|
||||
return new StreamDecrypterImpl(in, cipherProvider.get(), headerKey);
|
||||
return new StreamDecrypterImpl(in, cipherProvider.get(), 0, headerKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.briarproject.crypto;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.crypto.StreamDecrypter;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
@@ -17,11 +18,14 @@ 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.STREAM_HEADER_IV_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||
import static org.briarproject.util.ByteUtils.INT_64_BYTES;
|
||||
|
||||
class StreamDecrypterImpl implements StreamDecrypter {
|
||||
|
||||
private final InputStream in;
|
||||
private final AuthenticatedCipher cipher;
|
||||
private final long streamNumber;
|
||||
private final SecretKey streamHeaderKey;
|
||||
private final byte[] frameNonce, frameHeader, frameCiphertext;
|
||||
|
||||
@@ -30,9 +34,10 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
||||
private boolean finalFrame;
|
||||
|
||||
StreamDecrypterImpl(InputStream in, AuthenticatedCipher cipher,
|
||||
SecretKey streamHeaderKey) {
|
||||
long streamNumber, SecretKey streamHeaderKey) {
|
||||
this.in = in;
|
||||
this.cipher = cipher;
|
||||
this.streamNumber = streamNumber;
|
||||
this.streamHeaderKey = streamHeaderKey;
|
||||
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
||||
frameHeader = new byte[FRAME_HEADER_PLAINTEXT_LENGTH];
|
||||
@@ -42,6 +47,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
||||
finalFrame = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readFrame(byte[] payload) throws IOException {
|
||||
// The buffer must be big enough for a full-size frame
|
||||
if (payload.length < MAX_PAYLOAD_LENGTH)
|
||||
@@ -103,7 +109,6 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
||||
}
|
||||
|
||||
private void readStreamHeader() throws IOException {
|
||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||
byte[] streamHeaderPlaintext = new byte[SecretKey.LENGTH];
|
||||
// Read the stream header
|
||||
@@ -114,11 +119,14 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
||||
if (read == -1) throw new EOFException();
|
||||
offset += read;
|
||||
}
|
||||
// The nonce consists of the stream number followed by the IV
|
||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
||||
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce,
|
||||
INT_64_BYTES, STREAM_HEADER_IV_LENGTH);
|
||||
// Decrypt and authenticate the stream header
|
||||
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderIv, 0,
|
||||
STREAM_HEADER_IV_LENGTH);
|
||||
try {
|
||||
cipher.init(false, streamHeaderKey, streamHeaderIv);
|
||||
cipher.init(false, streamHeaderKey, streamHeaderNonce);
|
||||
int decrypted = cipher.process(streamHeaderCiphertext,
|
||||
STREAM_HEADER_IV_LENGTH, SecretKey.LENGTH + MAC_LENGTH,
|
||||
streamHeaderPlaintext, 0);
|
||||
|
||||
@@ -26,25 +26,28 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory {
|
||||
this.cipherProvider = cipherProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamEncrypter createStreamEncrypter(OutputStream out,
|
||||
StreamContext ctx) {
|
||||
AuthenticatedCipher cipher = cipherProvider.get();
|
||||
long streamNumber = ctx.getStreamNumber();
|
||||
byte[] tag = new byte[TAG_LENGTH];
|
||||
crypto.encodeTag(tag, ctx.getTagKey(), ctx.getStreamNumber());
|
||||
crypto.encodeTag(tag, ctx.getTagKey(), streamNumber);
|
||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
||||
SecretKey frameKey = crypto.generateSecretKey();
|
||||
return new StreamEncrypterImpl(out, cipher, tag, streamHeaderIv,
|
||||
ctx.getHeaderKey(), frameKey);
|
||||
return new StreamEncrypterImpl(out, cipher, streamNumber, tag,
|
||||
streamHeaderIv, ctx.getHeaderKey(), frameKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
||||
SecretKey headerKey) {
|
||||
AuthenticatedCipher cipher = cipherProvider.get();
|
||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
||||
SecretKey frameKey = crypto.generateSecretKey();
|
||||
return new StreamEncrypterImpl(out, cipher, null, streamHeaderIv,
|
||||
return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderIv,
|
||||
headerKey, frameKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.briarproject.crypto;
|
||||
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.crypto.StreamEncrypter;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -15,23 +17,28 @@ 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.STREAM_HEADER_IV_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||
import static org.briarproject.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||
import static org.briarproject.util.ByteUtils.INT_64_BYTES;
|
||||
|
||||
class StreamEncrypterImpl implements StreamEncrypter {
|
||||
|
||||
private final OutputStream out;
|
||||
private final AuthenticatedCipher cipher;
|
||||
private final SecretKey streamHeaderKey, frameKey;
|
||||
private final long streamNumber;
|
||||
private final byte[] tag, streamHeaderIv;
|
||||
private final byte[] frameNonce, frameHeader, framePlaintext, frameCiphertext;
|
||||
private final byte[] frameNonce, frameHeader;
|
||||
private final byte[] framePlaintext, frameCiphertext;
|
||||
|
||||
private long frameNumber;
|
||||
private boolean writeTag, writeStreamHeader;
|
||||
|
||||
StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
|
||||
byte[] tag, byte[] streamHeaderIv, SecretKey streamHeaderKey,
|
||||
SecretKey frameKey) {
|
||||
long streamNumber, @Nullable byte[] tag, byte[] streamHeaderIv,
|
||||
SecretKey streamHeaderKey, SecretKey frameKey) {
|
||||
this.out = out;
|
||||
this.cipher = cipher;
|
||||
this.streamNumber = streamNumber;
|
||||
this.tag = tag;
|
||||
this.streamHeaderIv = streamHeaderIv;
|
||||
this.streamHeaderKey = streamHeaderKey;
|
||||
@@ -45,6 +52,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
||||
writeStreamHeader = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFrame(byte[] payload, int payloadLength,
|
||||
int paddingLength, boolean finalFrame) throws IOException {
|
||||
if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH)
|
||||
@@ -91,18 +99,24 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
||||
}
|
||||
|
||||
private void writeTag() throws IOException {
|
||||
if (tag == null) throw new IllegalStateException();
|
||||
out.write(tag, 0, tag.length);
|
||||
writeTag = false;
|
||||
}
|
||||
|
||||
private void writeStreamHeader() throws IOException {
|
||||
// The nonce consists of the stream number followed by the IV
|
||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
||||
System.arraycopy(streamHeaderIv, 0, streamHeaderNonce, INT_64_BYTES,
|
||||
STREAM_HEADER_IV_LENGTH);
|
||||
byte[] streamHeaderPlaintext = frameKey.getBytes();
|
||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||
System.arraycopy(streamHeaderIv, 0, streamHeaderCiphertext, 0,
|
||||
STREAM_HEADER_IV_LENGTH);
|
||||
// Encrypt and authenticate the frame key
|
||||
try {
|
||||
cipher.init(true, streamHeaderKey, streamHeaderIv);
|
||||
cipher.init(true, streamHeaderKey, streamHeaderNonce);
|
||||
int encrypted = cipher.process(streamHeaderPlaintext, 0,
|
||||
SecretKey.LENGTH, streamHeaderCiphertext,
|
||||
STREAM_HEADER_IV_LENGTH);
|
||||
@@ -115,6 +129,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
||||
writeStreamHeader = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
// Write the tag if required
|
||||
if (writeTag) writeTag();
|
||||
|
||||
Reference in New Issue
Block a user