Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.bouncycastle.jsse.provider;

import org.bouncycastle.tls.crypto.TlsNonceGenerator;

final public class GcmTls12NonceGeneratorUtil
{
private static TlsNonceGeneratorFactory tlsNonceGeneratorFactory = null;

public static void setGcmTlsNonceGeneratorFactory(final TlsNonceGeneratorFactory factory)
{
tlsNonceGeneratorFactory = factory;
}

public static boolean isGcmFipsNonceGeneratorFactorySet()
{
return tlsNonceGeneratorFactory != null;
}

public static TlsNonceGenerator createGcmFipsNonceGenerator(final byte[] baseNonce, final int counterSizeInBits)
{
return tlsNonceGeneratorFactory != null
? tlsNonceGeneratorFactory.create(baseNonce, counterSizeInBits)
: null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.bouncycastle.jsse.provider;

import org.bouncycastle.tls.crypto.TlsNonceGenerator;

public interface TlsNonceGeneratorFactory
{
TlsNonceGenerator create(byte[] baseNonce, int counterSizeInBits);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
import org.bouncycastle.tls.crypto.TlsCryptoUtils;
import org.bouncycastle.tls.crypto.TlsDecodeResult;
import org.bouncycastle.tls.crypto.TlsEncodeResult;
import org.bouncycastle.tls.crypto.TlsNonceGenerator;
import org.bouncycastle.tls.crypto.TlsSecret;
import org.bouncycastle.util.Arrays;

import static org.bouncycastle.jsse.provider.GcmTls12NonceGeneratorUtil.createGcmFipsNonceGenerator;
import static org.bouncycastle.jsse.provider.GcmTls12NonceGeneratorUtil.isGcmFipsNonceGeneratorFactorySet;

/**
* A generic TLS 1.2 AEAD cipher.
*/
Expand All @@ -30,6 +34,8 @@ public final class TlsAEADCipher
private static final int NONCE_RFC7905 = 2;
private static final long SEQUENCE_NUMBER_PLACEHOLDER = -1L;

private static final byte[] EPOCH_1 = {0x00, 0x01};

private final TlsCryptoParameters cryptoParams;
private final int keySize;
private final int macSize;
Expand All @@ -43,6 +49,7 @@ public final class TlsAEADCipher

private final boolean isTLSv13;
private final int nonceMode;
private final TlsNonceGenerator gcmFipsNonceGenerator;

public TlsAEADCipher(TlsCryptoParameters cryptoParams, TlsAEADCipherImpl encryptCipher, TlsAEADCipherImpl decryptCipher,
int keySize, int macSize, int aeadType) throws IOException
Expand Down Expand Up @@ -91,6 +98,7 @@ public TlsAEADCipher(TlsCryptoParameters cryptoParams, TlsAEADCipherImpl encrypt
final boolean isServer = cryptoParams.isServer();
if (isTLSv13)
{
gcmFipsNonceGenerator = null;
rekeyCipher(securityParameters, decryptCipher, decryptNonce, !isServer);
rekeyCipher(securityParameters, encryptCipher, encryptNonce, isServer);
return;
Expand Down Expand Up @@ -121,6 +129,28 @@ public TlsAEADCipher(TlsCryptoParameters cryptoParams, TlsAEADCipherImpl encrypt
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}

if (AEAD_GCM == aeadType && isGcmFipsNonceGeneratorFactorySet())
{
final int nonceLength = fixed_iv_length + record_iv_length;
final byte[] baseNonce = Arrays.copyOf(encryptNonce, nonceLength);
final int counterSizeInBits;
if (negotiatedVersion.isDTLS())
{
counterSizeInBits = (record_iv_length - 2) * 8; // 48
baseNonce[baseNonce.length - 8] ^= EPOCH_1[0];
baseNonce[baseNonce.length - 7] ^= EPOCH_1[1];
}
else
{
counterSizeInBits = record_iv_length * 8; // 64
}
gcmFipsNonceGenerator = createGcmFipsNonceGenerator(baseNonce, counterSizeInBits);
}
else
{
gcmFipsNonceGenerator = null;
}
}

public int getCiphertextDecodeLimit(int plaintextLimit)
Expand Down Expand Up @@ -154,24 +184,33 @@ public int getPlaintextEncodeLimit(int ciphertextLimit)
public TlsEncodeResult encodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, byte[] plaintext, int plaintextOffset, int plaintextLength) throws IOException
{
byte[] nonce = new byte[encryptNonce.length + record_iv_length];
final int nonceSize = encryptNonce.length + record_iv_length;
final byte[] nonce;

switch (nonceMode)
if (null != gcmFipsNonceGenerator)
{
case NONCE_RFC5288:
System.arraycopy(encryptNonce, 0, nonce, 0, encryptNonce.length);
// RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
TlsUtils.writeUint64(seqNo, nonce, encryptNonce.length);
break;
case NONCE_RFC7905:
TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8);
for (int i = 0; i < encryptNonce.length; ++i)
nonce = gcmFipsNonceGenerator.generateNonce(nonceSize);
}
else
{
nonce = new byte[nonceSize];
switch (nonceMode)
{
nonce[i] ^= encryptNonce[i];
case NONCE_RFC5288:
System.arraycopy(encryptNonce, 0, nonce, 0, encryptNonce.length);
// RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
TlsUtils.writeUint64(seqNo, nonce, encryptNonce.length);
break;
case NONCE_RFC7905:
TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8);
for (int i = 0; i < encryptNonce.length; ++i)
{
nonce[i] ^= encryptNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}

// TODO[tls13, cid] If we support adding padding to (D)TLSInnerPlaintext, this will need review
Expand Down
8 changes: 8 additions & 0 deletions tls/src/test/java/org/bouncycastle/tls/test/AllTests.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bouncycastle.tls.test;

import org.bouncycastle.jsse.provider.GcmTls12NonceGeneratorUtil;
import org.bouncycastle.test.PrintTestResult;

import junit.extensions.TestSetup;
Expand All @@ -14,6 +15,13 @@ public static void main(String[] args)
throws Exception
{
PrintTestResult.printResult(junit.textui.TestRunner.run(suite()));
PrintTestResult.printResult(junit.textui.TestRunner.run(suiteWithCustomNonceGeneratorForTls12()));
}

public static Test suiteWithCustomNonceGeneratorForTls12() throws Exception
{
GcmTls12NonceGeneratorUtil.setGcmTlsNonceGeneratorFactory(TestTlsNonceGeneratorFactory.INSTANCE);
return suite();
}

public static Test suite()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.bouncycastle.tls.test;

import org.bouncycastle.tls.crypto.TlsNonceGenerator;

import java.util.Arrays;

class TestNonceGenerator implements TlsNonceGenerator
{
private final byte[] baseNonce;
private final long counterMask;
private final int counterBytes;

private long counterValue;
private boolean counterExhausted;

TestNonceGenerator(final byte[] baseNonce, final int counterBits)
{
this.baseNonce = Arrays.copyOf(baseNonce, baseNonce.length);
this.counterMask = -1L >>> (64 - counterBits);
this.counterBytes = (counterBits + 7) / 8;

this.counterValue = 0L;
this.counterExhausted = false;
}

@Override
public byte[] generateNonce(final int size)
{
if (size != baseNonce.length)
{
throw new IllegalArgumentException("requested length is not equal to the length of the base nonce.");
}

if (counterExhausted)
{
throw new IllegalStateException("TLS nonce generator exhausted");
}

final byte[] nonce = Arrays.copyOf(baseNonce, baseNonce.length);
final int offset = baseNonce.length - counterBytes;

for (int i = 0; i < counterBytes; i++)
{
nonce[offset + i] ^= (byte)(counterValue >>> ((counterBytes - 1 - i) * 8));
}

counterExhausted |= ((++counterValue & counterMask) == 0);

return nonce;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.bouncycastle.tls.test;

import org.bouncycastle.jsse.provider.TlsNonceGeneratorFactory;
import org.bouncycastle.tls.crypto.TlsNonceGenerator;

class TestTlsNonceGeneratorFactory implements TlsNonceGeneratorFactory {
public static final TlsNonceGeneratorFactory INSTANCE = new TestTlsNonceGeneratorFactory();

private TestTlsNonceGeneratorFactory()
{
// no op
}

@Override
public TlsNonceGenerator create(final byte[] baseNonce, final int counterSizeInBits)
{
return new TestNonceGenerator(baseNonce, counterSizeInBits);
}
}