Skip to content

Commit

Permalink
Merge branch 'master' of git.bouncycastle.org:bc-java
Browse files Browse the repository at this point in the history
  • Loading branch information
peterdettman committed Sep 18, 2013
2 parents 36d54ef + 1edaac9 commit 60f3b60
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 35 deletions.
3 changes: 2 additions & 1 deletion CONTRIBUTORS.html
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@
<li>Brian Carlstrom &lt;bdc&#064carlstrom.com&gt; compliance patches for some JCA/JCE keystore and cipher classes, miscellaneous code quality improvements, intial provider PBKDF2WithHmacSHA1 SecretKeyFactory.</li>
<li>Samuel Lid&eacute;n Borell &lt;samuel&#064primekey.se&gt; patch to add DSTU-4145 to DefaultSignatureAlgorithmFinder</li>
<li>Sergio Demian Lerner &lt;sergiolerner&#064certimix.com&gt; pointing out isInfinity issue in ECDSASigner signature verification.</li>
<li>Tim Whittington &lt;Tim.Whittington&#064orionhealth.com&gt; patch to remove extra init call in CMac, additional of Memoable interface for Digest classes, initial implementation of GMAC, further correctness tests for IV and reset processing in OCB, CCM, and block cipher reset. Initial implementation of Skein and Threefish. Documentation updates. Added OCB support to Noekeon and CAST6 in the provider, exception testing for CTS.</li>
<li>Tim Whittington &lt;Tim.Whittington&#064orionhealth.com&gt; patch to remove extra init call in CMac, additional of Memoable interface for Digest classes, initial implementation of GMAC, further correctness tests for IV and reset processing in OCB, CCM, and block cipher reset. Initial implementation of Skein, XSalsa20, ChaCha, reduced round Salsa20 and Threefish. Documentation updates. Added OCB support to Noekeon and CAST6 in the provider, exception testing for CTS, optimisations for CCM.</li>
<li>Marcus Lundblad &lt;marcus.lundblad&#064primekey.se&gt; patch for working arnound JDK jarsigner TSP bug, optional setting of IssuerSerial in TimeStampTokenGenerator.</li>
<li>Andrey Zhozhin &lt;zhozhin&#064xrm.ru&gt; patch for override of TSP SignerInfo attributes.</li>
<li>Sergey Tiunov &lt;t5555d&#064gmail.com&gt; initial cut of DVCS classes.</li>
Expand All @@ -336,6 +336,7 @@
<li>Eric M&uuml;ller &lt;eric.mueller&#064sage.de&gt; additional standard algorithm name lookups in JcaPEMKeyConverter.</li>
<li>Mathias Herberts &lt;Mathias.Herberts&#064gmail.com&gt; fix to inOff usage in RFC3394WrapEngine.</li>
<li>Daniil Ivanov &lt;daniil.ivanov&#064gmail.com&gt; addition of provider support for GOST HMAC SecretKeyFactory.</li>
<li>Daniele Grasso &lt;daniele.grasso86&#064gmail.com&gt; contributions to final Key calculation code for SRP6.</li>
</ul>
</body>
</html>
117 changes: 84 additions & 33 deletions core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public class CCMBlockCipher
private int macSize;
private CipherParameters keyParam;
private byte[] macBlock;
private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
private ByteArrayOutputStream data = new ByteArrayOutputStream();
private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream();
private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream();

/**
* Basic constructor.
Expand Down Expand Up @@ -138,14 +138,11 @@ public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
public int doFinal(byte[] out, int outOff)
throws IllegalStateException, InvalidCipherTextException
{
byte[] text = data.toByteArray();
byte[] enc = processPacket(text, 0, text.length);

System.arraycopy(enc, 0, out, outOff, enc.length);
int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff);

reset();

return enc.length;
return len;
}

public void reset()
Expand Down Expand Up @@ -187,8 +184,54 @@ public int getOutputSize(int len)
return totalData < macSize ? 0 : totalData - macSize;
}

/**
* Process a packet of data for either CCM decryption or encryption.
*
* @param in data for processing.
* @param inOff offset at which data starts in the input array.
* @param inLen length of the data in the input array.
* @return a byte array containing the processed input..
* @throws IllegalStateException if the cipher is not appropriately set up.
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
*/
public byte[] processPacket(byte[] in, int inOff, int inLen)
throws IllegalStateException, InvalidCipherTextException
{
byte[] output;

if (forEncryption)
{
output = new byte[inLen + macSize];
}
else
{
if (inLen < macSize)
{
throw new InvalidCipherTextException("data too short");
}
output = new byte[inLen - macSize];
}

processPacket(in, inOff, inLen, output, 0);

return output;
}

/**
* Process a packet of data for either CCM decryption or encryption.
*
* @param in data for processing.
* @param inOff offset at which data starts in the input array.
* @param inLen length of the data in the input array.
* @param output output array.
* @param outOff offset into output array to start putting processed bytes.
* @return the number of bytes added to output.
* @throws IllegalStateException if the cipher is not appropriately set up.
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
* @throws DataLengthException if output buffer too short.
*/
public int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff)
throws IllegalStateException, InvalidCipherTextException, DataLengthException
{
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
// Need to keep the CTR and CBC Mac parts around and reset
Expand All @@ -215,14 +258,13 @@ public byte[] processPacket(byte[] in, int inOff, int inLen)
BlockCipher ctrCipher = new SICBlockCipher(cipher);
ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));

int index = inOff;
int outOff = 0;
byte[] output;
int outputLen;
int inIndex = inOff;
int outIndex = outOff;

if (forEncryption)
{
int outputLen = inLen + macSize;
output = new byte[outputLen];
outputLen = inLen + macSize;
if (output.length < (outputLen + outOff))
{
throw new DataLengthException("Output buffer too short.");
Expand All @@ -232,33 +274,30 @@ public byte[] processPacket(byte[] in, int inOff, int inLen)

ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0

while (index < inLen - blockSize) // S1...
while (inIndex < (inOff + inLen - blockSize)) // S1...
{
ctrCipher.processBlock(in, index, output, outOff);
outOff += blockSize;
index += blockSize;
ctrCipher.processBlock(in, inIndex, output, outIndex);
outIndex += blockSize;
inIndex += blockSize;
}

byte[] block = new byte[blockSize];

System.arraycopy(in, index, block, 0, inLen - index);
System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex);

ctrCipher.processBlock(block, 0, block, 0);

System.arraycopy(block, 0, output, outOff, inLen - index);

outOff += inLen - index;
System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex);

System.arraycopy(macBlock, 0, output, outOff, output.length - outOff);
System.arraycopy(macBlock, 0, output, outOff + inLen, macSize);
}
else
{
if (inLen < macSize)
{
throw new InvalidCipherTextException("data too short");
}
int outputLen = inLen - macSize;
output = new byte[outputLen];
outputLen = inLen - macSize;
if (output.length < (outputLen + outOff))
{
throw new DataLengthException("Output buffer too short.");
Expand All @@ -273,32 +312,32 @@ public byte[] processPacket(byte[] in, int inOff, int inLen)
macBlock[i] = 0;
}

while (outOff < output.length - blockSize)
while (inIndex < (inOff + outputLen - blockSize))
{
ctrCipher.processBlock(in, index, output, outOff);
outOff += blockSize;
index += blockSize;
ctrCipher.processBlock(in, inIndex, output, outIndex);
outIndex += blockSize;
inIndex += blockSize;
}

byte[] block = new byte[blockSize];

System.arraycopy(in, index, block, 0, output.length - outOff);
System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff));

ctrCipher.processBlock(block, 0, block, 0);

System.arraycopy(block, 0, output, outOff, output.length - outOff);
System.arraycopy(block, 0, output, outIndex, outputLen - (inIndex - inOff));

byte[] calculatedMacBlock = new byte[blockSize];

calculateMac(output, 0, output.length, calculatedMacBlock);
calculateMac(output, outOff, outputLen, calculatedMacBlock);

if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
{
throw new InvalidCipherTextException("mac check in CCM failed");
}
}

return output;
return outputLen;
}

private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
Expand Down Expand Up @@ -367,8 +406,7 @@ private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
}
if (associatedText.size() > 0)
{
byte[] tmp = associatedText.toByteArray();
cMac.update(tmp, 0, tmp.length);
cMac.update(associatedText.getBuffer(), 0, associatedText.size());
}

extra = (extra + textLength) % 16;
Expand Down Expand Up @@ -398,4 +436,17 @@ private boolean hasAssociatedText()
{
return getAssociatedTextLength() > 0;
}

private class ExposedByteArrayOutputStream
extends ByteArrayOutputStream
{
public ExposedByteArrayOutputStream()
{
}

public byte[] getBuffer()
{
return this.buf;
}
}
}
46 changes: 45 additions & 1 deletion core/src/test/java/org/bouncycastle/crypto/test/CCMTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,38 @@ public void performTest()
// long data test
//
checkVectors(4, ccm, K4, 112, N4, A4, A4, T5, C5);


// decryption with output specified, non-zero offset.
ccm.init(false, new AEADParameters(new KeyParameter(K2), 48, N2, A2));

byte[] inBuf = new byte[C2.length + 10];
byte[] outBuf = new byte[ccm.getOutputSize(C2.length) + 10];

System.arraycopy(C2, 0, inBuf, 10, C2.length);

int len = ccm.processPacket(inBuf, 10, C2.length, outBuf, 10);
byte[] out = ccm.processPacket(C2, 0, C2.length);

if (len != out.length || !isEqual(out, outBuf, 10))
{
fail("decryption output incorrect");
}

// encryption with output specified, non-zero offset.
ccm.init(true, new AEADParameters(new KeyParameter(K2), 48, N2, A2));

int inLen = len;
inBuf = outBuf;
outBuf = new byte[ccm.getOutputSize(inLen) + 10];

len = ccm.processPacket(inBuf, 10, inLen, outBuf, 10);
out = ccm.processPacket(inBuf, 10, inLen);

if (len != out.length || !isEqual(out, outBuf, 10))
{
fail("encryption output incorrect");
}

//
// exception tests
//
Expand Down Expand Up @@ -123,6 +154,19 @@ public void performTest()
AEADTestUtil.testTampering(this, ccm, new AEADParameters(new KeyParameter(K1), 32, N2));
}

private boolean isEqual(byte[] exp, byte[] other, int off)
{
for (int i = 0; i != exp.length; i++)
{
if (exp[i] != other[off + i])
{
return false;
}
}

return true;
}

private void checkVectors(
int count,
CCMBlockCipher ccm,
Expand Down

0 comments on commit 60f3b60

Please sign in to comment.