summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main/java/org/bouncycastle/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java108
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java68
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java326
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java163
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java299
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java130
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java124
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java67
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java174
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java59
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java23
42 files changed, 1649 insertions, 583 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
index dd056ac..8e41e49 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -48,13 +48,13 @@ public class BufferedBlockCipher
pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
- if (pgpCFB)
+ if (pgpCFB || cipher instanceof StreamCipher)
{
partialBlockOkay = true;
}
else
{
- partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("GCFB", idx) ||name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
+ partialBlockOkay = (idx > 0 && (name.startsWith("OpenPGP", idx)));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java
new file mode 100644
index 0000000..f8cc648
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Ciphers producing a key stream which can be reset to particular points in the stream implement this.
+ */
+public interface SkippingCipher
+{
+ /**
+ * Skip numberOfBytes forwards, or backwards.
+ *
+ * @param numberOfBytes the number of bytes to skip (positive forward, negative backwards).
+ * @return the number of bytes actually skipped.
+ * @throws java.lang.IllegalArgumentException if numberOfBytes is an invalid value.
+ */
+ long skip(long numberOfBytes);
+
+ /**
+ * Reset the cipher and then skip forward to a given position.
+ *
+ * @param position the number of bytes in to set the cipher state to.
+ * @return the byte position moved to.
+ */
+ long seekTo(long position);
+
+ /**
+ * Return the current "position" of the cipher
+ *
+ * @return the current byte position.
+ */
+ long getPosition();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java
new file mode 100644
index 0000000..a707a81
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.crypto;
+
+/**
+ * General interface for a stream cipher that supports skipping.
+ */
+public interface SkippingStreamCipher
+ extends StreamCipher, SkippingCipher
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
index 8fdd232..09aadfb 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
@@ -1,108 +1,58 @@
package org.bouncycastle.crypto;
/**
- * a wrapper for block ciphers with a single byte block size, so that they
- * can be treated like stream ciphers.
+ * A parent class for block cipher modes that do not require block aligned data to be processed, but can function in
+ * a streaming mode.
*/
-public class StreamBlockCipher
- implements StreamCipher
+public abstract class StreamBlockCipher
+ implements BlockCipher, StreamCipher
{
- private BlockCipher cipher;
+ private final BlockCipher cipher;
- private byte[] oneByte = new byte[1];
-
- /**
- * basic constructor.
- *
- * @param cipher the block cipher to be wrapped.
- * @exception IllegalArgumentException if the cipher has a block size other than
- * one.
- */
- public StreamBlockCipher(
- BlockCipher cipher)
+ protected StreamBlockCipher(BlockCipher cipher)
{
- if (cipher.getBlockSize() != 1)
- {
- throw new IllegalArgumentException("block cipher block size != 1.");
- }
-
this.cipher = cipher;
}
/**
- * initialise the underlying cipher.
+ * return the underlying block cipher that we are wrapping.
*
- * @param forEncryption true if we are setting up for encryption, false otherwise.
- * @param params the necessary parameters for the underlying cipher to be initialised.
+ * @return the underlying block cipher that we are wrapping.
*/
- public void init(
- boolean forEncryption,
- CipherParameters params)
+ public BlockCipher getUnderlyingCipher()
{
- cipher.init(forEncryption, params);
+ return cipher;
}
- /**
- * return the name of the algorithm we are wrapping.
- *
- * @return the name of the algorithm we are wrapping.
- */
- public String getAlgorithmName()
+ public final byte returnByte(byte in)
{
- return cipher.getAlgorithmName();
+ return calculateByte(in);
}
- /**
- * encrypt/decrypt a single byte returning the result.
- *
- * @param in the byte to be processed.
- * @return the result of processing the input byte.
- */
- public byte returnByte(
- byte in)
- {
- oneByte[0] = in;
-
- cipher.processBlock(oneByte, 0, oneByte, 0);
-
- return oneByte[0];
- }
-
- /**
- * process a block of bytes from in putting the result into out.
- *
- * @param in the input byte array.
- * @param inOff the offset into the in array where the data to be processed starts.
- * @param len the number of bytes to be processed.
- * @param out the output buffer the processed bytes go into.
- * @param outOff the offset into the output byte array the processed data stars at.
- * @exception DataLengthException if the output buffer is too small.
- */
- public void processBytes(
- byte[] in,
- int inOff,
- int len,
- byte[] out,
- int outOff)
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
throws DataLengthException
{
if (outOff + len > out.length)
{
- throw new DataLengthException("output buffer too small in processBytes()");
+ throw new DataLengthException("output buffer too short");
}
- for (int i = 0; i != len; i++)
+ if (inOff + len > in.length)
{
- cipher.processBlock(in, inOff + i, out, outOff + i);
+ throw new DataLengthException("input buffer too small");
}
- }
- /**
- * reset the underlying cipher. This leaves it in the same state
- * it was at after the last init (if there was one).
- */
- public void reset()
- {
- cipher.reset();
+ int inStart = inOff;
+ int inEnd = inOff + len;
+ int outStart = outOff;
+
+ while (inStart < inEnd)
+ {
+ out[outStart++] = calculateByte(in[inStart++]);
+ }
+
+ return len;
}
-}
+
+ protected abstract byte calculateByte(byte b);
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java
index 2a55d4f..c1255e9 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java
@@ -40,9 +40,10 @@ public interface StreamCipher
* @param len the number of bytes to be processed.
* @param out the output buffer the processed bytes go into.
* @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes produced - should always be len.
* @exception DataLengthException if the output buffer is too small.
*/
- public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
throws DataLengthException;
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java
new file mode 100644
index 0000000..d79fece
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.crypto.digests;
+
+/**
+ * Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where
+ * you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the
+ * internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the
+ * entire message.
+ */
+public interface EncodableDigest
+{
+ /**
+ * Return an encoded byte array for the digest's internal state
+ *
+ * @return an encoding of the digests internal state.
+ */
+ byte[] getEncodedState();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
index 15f3ebb..29692ba 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
* base implementation of MD4 family style digest as outlined in
@@ -11,8 +12,9 @@ public abstract class GeneralDigest
implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 64;
- private byte[] xBuf;
- private int xBufOff;
+
+ private final byte[] xBuf = new byte[4];
+ private int xBufOff;
private long byteCount;
@@ -21,7 +23,6 @@ public abstract class GeneralDigest
*/
protected GeneralDigest()
{
- xBuf = new byte[4];
xBufOff = 0;
}
@@ -32,11 +33,16 @@ public abstract class GeneralDigest
*/
protected GeneralDigest(GeneralDigest t)
{
- xBuf = new byte[t.xBuf.length];
-
copyIn(t);
}
+ protected GeneralDigest(byte[] encodedState)
+ {
+ System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length);
+ xBufOff = Pack.bigEndianToInt(encodedState, 4);
+ byteCount = Pack.bigEndianToLong(encodedState, 8);
+ }
+
protected void copyIn(GeneralDigest t)
{
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
@@ -129,6 +135,13 @@ public abstract class GeneralDigest
}
}
+ protected void populateState(byte[] state)
+ {
+ System.arraycopy(xBuf, 0, state, 0, xBufOff);
+ Pack.intToBigEndian(xBufOff, state, 4);
+ Pack.longToBigEndian(byteCount, state, 8);
+ }
+
public int getByteLength()
{
return BYTE_LENGTH;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
index 5c79e4e..8ea474b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
@@ -1,18 +1,18 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
* Base class for SHA-384 and SHA-512.
*/
public abstract class LongDigest
- implements ExtendedDigest, Memoable
+ implements ExtendedDigest, Memoable, EncodableDigest
{
private static final int BYTE_LENGTH = 128;
-
- private byte[] xBuf;
+
+ private byte[] xBuf = new byte[8];
private int xBufOff;
private long byteCount1;
@@ -28,7 +28,6 @@ public abstract class LongDigest
*/
protected LongDigest()
{
- xBuf = new byte[8];
xBufOff = 0;
reset();
@@ -41,8 +40,6 @@ public abstract class LongDigest
*/
protected LongDigest(LongDigest t)
{
- xBuf = new byte[t.xBuf.length];
-
copyIn(t);
}
@@ -67,6 +64,56 @@ public abstract class LongDigest
wOff = t.wOff;
}
+ protected void populateState(byte[] state)
+ {
+ System.arraycopy(xBuf, 0, state, 0, xBufOff);
+ Pack.intToBigEndian(xBufOff, state, 8);
+ Pack.longToBigEndian(byteCount1, state, 12);
+ Pack.longToBigEndian(byteCount2, state, 20);
+ Pack.longToBigEndian(H1, state, 28);
+ Pack.longToBigEndian(H2, state, 36);
+ Pack.longToBigEndian(H3, state, 44);
+ Pack.longToBigEndian(H4, state, 52);
+ Pack.longToBigEndian(H5, state, 60);
+ Pack.longToBigEndian(H6, state, 68);
+ Pack.longToBigEndian(H7, state, 76);
+ Pack.longToBigEndian(H8, state, 84);
+
+ Pack.intToBigEndian(wOff, state, 92);
+ for (int i = 0; i < wOff; i++)
+ {
+ Pack.longToBigEndian(W[i], state, 96 + (i * 8));
+ }
+ }
+
+ protected void restoreState(byte[] encodedState)
+ {
+ xBufOff = Pack.bigEndianToInt(encodedState, 8);
+ System.arraycopy(encodedState, 0, xBuf, 0, xBufOff);
+ byteCount1 = Pack.bigEndianToLong(encodedState, 12);
+ byteCount2 = Pack.bigEndianToLong(encodedState, 20);
+
+ H1 = Pack.bigEndianToLong(encodedState, 28);
+ H2 = Pack.bigEndianToLong(encodedState, 36);
+ H3 = Pack.bigEndianToLong(encodedState, 44);
+ H4 = Pack.bigEndianToLong(encodedState, 52);
+ H5 = Pack.bigEndianToLong(encodedState, 60);
+ H6 = Pack.bigEndianToLong(encodedState, 68);
+ H7 = Pack.bigEndianToLong(encodedState, 76);
+ H8 = Pack.bigEndianToLong(encodedState, 84);
+
+ wOff = Pack.bigEndianToInt(encodedState, 92);
+ for (int i = 0; i < wOff; i++)
+ {
+ W[i] = Pack.bigEndianToLong(encodedState, 96 + (i * 8));
+ }
+ }
+
+ protected int getEncodedStateSize()
+ {
+ return 96 + (wOff * 8);
+ }
+
public void update(
byte in)
{
@@ -165,7 +212,7 @@ public abstract class LongDigest
{
return BYTE_LENGTH;
}
-
+
protected void processWord(
byte[] in,
int inOff)
@@ -228,7 +275,7 @@ public abstract class LongDigest
long g = H7;
long h = H8;
- int t = 0;
+ int t = 0;
for(int i = 0; i < 10; i ++)
{
// t = 8 * i
@@ -271,7 +318,7 @@ public abstract class LongDigest
e += a;
a += Sum0(b) + Maj(b, c, d);
}
-
+
H1 += a;
H2 += b;
H3 += c;
@@ -358,4 +405,5 @@ public abstract class LongDigest
0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
};
+
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
index 21b1024..450dda4 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
* implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
@@ -11,6 +11,7 @@ import org.bouncycastle.util.Memoable;
*/
public class SHA1Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 20;
@@ -38,6 +39,23 @@ public class SHA1Digest
copyIn(t);
}
+ public SHA1Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+
+ xOff = Pack.bigEndianToInt(encodedState, 36);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4));
+ }
+ }
+
private void copyIn(SHA1Digest t)
{
H1 = t.H1;
@@ -302,6 +320,27 @@ public class SHA1Digest
super.copyIn(d);
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[40 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(xOff, state, 36);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 40 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
index d430321..4f2b284 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -1,8 +1,8 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
@@ -18,6 +18,7 @@ import org.bouncycastle.util.Memoable;
*/
public class SHA224Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 28;
@@ -62,6 +63,26 @@ public class SHA224Digest
xOff = t.xOff;
}
+ public SHA224Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+ H6 = Pack.bigEndianToInt(encodedState, 36);
+ H7 = Pack.bigEndianToInt(encodedState, 40);
+ H8 = Pack.bigEndianToInt(encodedState, 44);
+
+ xOff = Pack.bigEndianToInt(encodedState, 48);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+ }
+ }
+
public String getAlgorithmName()
{
return "SHA-224";
@@ -307,5 +328,29 @@ public class SHA224Digest
doCopy(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[52 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(H6, state, 36);
+ Pack.intToBigEndian(H7, state, 40);
+ Pack.intToBigEndian(H8, state, 44);
+ Pack.intToBigEndian(xOff, state, 48);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
index a2ceda3..600d234 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -1,8 +1,8 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
@@ -18,6 +18,7 @@ import org.bouncycastle.util.Memoable;
*/
public class SHA256Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 32;
@@ -62,6 +63,27 @@ public class SHA256Digest
xOff = t.xOff;
}
+ public SHA256Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+ H6 = Pack.bigEndianToInt(encodedState, 36);
+ H7 = Pack.bigEndianToInt(encodedState, 40);
+ H8 = Pack.bigEndianToInt(encodedState, 44);
+
+ xOff = Pack.bigEndianToInt(encodedState, 48);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+ }
+ }
+
+
public String getAlgorithmName()
{
return "SHA-256";
@@ -310,5 +332,29 @@ public class SHA256Digest
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[52 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(H6, state, 36);
+ Pack.intToBigEndian(H7, state, 40);
+ Pack.intToBigEndian(H8, state, 44);
+ Pack.intToBigEndian(xOff, state, 48);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
index 75d195d..fc9fa1e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
@@ -36,6 +36,11 @@ public class SHA384Digest
super(t);
}
+ public SHA384Digest(byte[] encodedState)
+ {
+ restoreState(encodedState);
+ }
+
public String getAlgorithmName()
{
return "SHA-384";
@@ -96,4 +101,11 @@ public class SHA384Digest
super.copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] encoded = new byte[getEncodedStateSize()];
+ super.populateState(encoded);
+ return encoded;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
index 7db63ad..644bafa 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
@@ -36,6 +36,11 @@ public class SHA512Digest
super(t);
}
+ public SHA512Digest(byte[] encodedState)
+ {
+ restoreState(encodedState);
+ }
+
public String getAlgorithmName()
{
return "SHA-512";
@@ -98,5 +103,12 @@ public class SHA512Digest
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] encoded = new byte[getEncodedStateSize()];
+ super.populateState(encoded);
+ return encoded;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
new file mode 100644
index 0000000..3b4b2e6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
@@ -0,0 +1,326 @@
+package org.bouncycastle.crypto.ec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+// BEGIN android-removed
+// import org.bouncycastle.math.ec.custom.djb.Curve25519;
+// END android-removed
+import org.bouncycastle.math.ec.custom.sec.SecP192K1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP192R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP224K1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP224R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class CustomNamedCurves
+{
+ private static ECCurve configureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p)
+ {
+ return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create();
+ }
+
+ // BEGIN android-removed
+ // /*
+ // * curve25519
+ // */
+ // static X9ECParametersHolder curve25519 = new X9ECParametersHolder()
+ // {
+ // protected X9ECParameters createParameters()
+ // {
+ // byte[] S = null;
+ // ECCurve curve = configureCurve(new Curve25519());
+ //
+ // /*
+ // * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
+ // * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
+ // *
+ // * The Curve25519 paper doesn't say which of the two possible y values the base
+ // * point has. The choice here is guided by language in the Ed25519 paper.
+ // *
+ // * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14)
+ // */
+ // ECPoint G = curve.decodePoint(Hex.decode("04"
+ // + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+ // + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
+ //
+ // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ // }
+ // };
+ // END android-removed
+
+ /*
+ * secp192k1
+ */
+ static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+ new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+ new BigInteger[]{
+ new BigInteger("71169be7330b3038edb025f1", 16),
+ new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+ new BigInteger[]{
+ new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+ new BigInteger("71169be7330b3038edb025f1", 16) },
+ new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+ new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+ 208);
+ ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv);
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp192r1
+ */
+ static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+ ECCurve curve = configureCurve(new SecP192R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp224k1
+ */
+ static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+ new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+ new BigInteger[]{
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+ new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+ new BigInteger[]{
+ new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+ new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+ new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+ 240);
+ ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv);
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp224r1
+ */
+ static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+ ECCurve curve = configureCurve(new SecP224R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp256k1
+ */
+ static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+ new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+ new BigInteger[]{
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+ new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+ new BigInteger[]{
+ new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+ new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+ new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+ 272);
+ ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv);
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp256r1
+ */
+ static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+ ECCurve curve = configureCurve(new SecP256R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp384r1
+ */
+ static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+ ECCurve curve = configureCurve(new SecP384R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp521r1
+ */
+ static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+ ECCurve curve = configureCurve(new SecP521R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ static final Hashtable nameToCurve = new Hashtable();
+ static final Hashtable nameToOID = new Hashtable();
+ static final Hashtable oidToCurve = new Hashtable();
+ static final Hashtable oidToName = new Hashtable();
+
+ static void defineCurve(String name, X9ECParametersHolder holder)
+ {
+ nameToCurve.put(name, holder);
+ }
+
+ static void defineCurveWithOID(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ nameToCurve.put(name, holder);
+ nameToOID.put(name, oid);
+ oidToName.put(oid, name);
+ oidToCurve.put(oid, holder);
+ }
+
+ static void defineCurveAlias(String alias, ASN1ObjectIdentifier oid)
+ {
+ alias = Strings.toLowerCase(alias);
+ nameToOID.put(alias, oid);
+ nameToCurve.put(alias, oidToCurve.get(oid));
+ }
+
+ static
+ {
+ // BEGIN android-removed
+ // defineCurve("curve25519", curve25519);
+ // END android-removed
+
+ defineCurveWithOID("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+ defineCurveWithOID("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+ defineCurveWithOID("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+ defineCurveWithOID("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1);
+ defineCurveWithOID("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+ defineCurveWithOID("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
+ defineCurveWithOID("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1);
+ defineCurveWithOID("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1);
+
+ defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1);
+ defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1);
+ defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1);
+ defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1);
+ defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1);
+ }
+
+ public static X9ECParameters getByName(String name)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve.get(Strings.toLowerCase(name));
+ return holder == null ? null : holder.getParameters();
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by the passed in object
+ * identifier. Null if the curve isn't present.
+ *
+ * @param oid
+ * an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters getByOID(ASN1ObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve.get(oid);
+ return holder == null ? null : holder.getParameters();
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null if there is no object
+ * identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static ASN1ObjectIdentifier getOID(String name)
+ {
+ return (ASN1ObjectIdentifier)nameToOID.get(Strings.toLowerCase(name));
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static String getName(ASN1ObjectIdentifier oid)
+ {
+ return (String)oidToName.get(oid);
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves contained in this structure.
+ */
+ public static Enumeration getNames()
+ {
+ return nameToCurve.keys();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
index d8ec62b..c78b1a5 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -34,6 +34,8 @@ public class PKCS1Encoding
private boolean forEncryption;
private boolean forPrivateKey;
private boolean useStrictLength;
+ private int pLen = -1;
+ private byte[] fallback = null;
/**
* Basic constructor.
@@ -46,6 +48,42 @@ public class PKCS1Encoding
this.useStrictLength = useStrict();
}
+ /**
+ * Constructor for decryption with a fixed plaintext length.
+ *
+ * @param cipher The cipher to use for cryptographic operation.
+ * @param pLen Length of the expected plaintext.
+ */
+ public PKCS1Encoding(
+ AsymmetricBlockCipher cipher,
+ int pLen)
+ {
+ this.engine = cipher;
+ this.useStrictLength = useStrict();
+ this.pLen = pLen;
+ }
+
+ /**
+ * Constructor for decryption with a fixed plaintext length and a fallback
+ * value that is returned, if the padding is incorrect.
+ *
+ * @param cipher
+ * The cipher to use for cryptographic operation.
+ * @param fallback
+ * The fallback value, we don't to a arraycopy here.
+ */
+ public PKCS1Encoding(
+ AsymmetricBlockCipher cipher,
+ byte[] fallback)
+ {
+ this.engine = cipher;
+ this.useStrictLength = useStrict();
+ this.fallback = fallback;
+ this.pLen = fallback.length;
+ }
+
+
+
//
// for J2ME compatibility
//
@@ -183,6 +221,121 @@ public class PKCS1Encoding
return engine.processBlock(block, 0, block.length);
}
+
+ /**
+ * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
+ * for encryption.
+ *
+ * @param encoded The Plaintext.
+ * @param pLen Expected length of the plaintext.
+ * @return Either 0, if the encoding is correct, or -1, if it is incorrect.
+ */
+ private static int checkPkcs1Encoding(byte[] encoded, int pLen) {
+ int correct = 0;
+ /*
+ * Check if the first two bytes are 0 2
+ */
+ correct |= (encoded[0] ^ 2);
+
+ /*
+ * Now the padding check, check for no 0 byte in the padding
+ */
+ int plen = encoded.length - (
+ pLen /* Lenght of the PMS */
+ + 1 /* Final 0-byte before PMS */
+ );
+
+ for (int i = 1; i < plen; i++) {
+ int tmp = encoded[i];
+ tmp |= tmp >> 1;
+ tmp |= tmp >> 2;
+ tmp |= tmp >> 4;
+ correct |= (tmp & 1) - 1;
+ }
+
+ /*
+ * Make sure the padding ends with a 0 byte.
+ */
+ correct |= encoded[encoded.length - (pLen +1)];
+
+ /*
+ * Return 0 or 1, depending on the result.
+ */
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ return ~((correct & 1) - 1);
+ }
+
+
+ /**
+ * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
+ *
+ * @param in The encrypted block.
+ * @param inOff Offset in the encrypted block.
+ * @param inLen Length of the encrypted block.
+ * //@param pLen Length of the desired output.
+ * @return The plaintext without padding, or a random value if the padding was incorrect.
+ *
+ * @throws InvalidCipherTextException
+ */
+ private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen)
+ throws InvalidCipherTextException
+ {
+ if (!forPrivateKey)
+ {
+ throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
+ }
+
+ byte[] block = engine.processBlock(in, inOff, inLen);
+ byte[] random = null;
+ if (this.fallback == null)
+ {
+ random = new byte[this.pLen];
+ this.random.nextBytes(random);
+ }
+ else
+ {
+ random = fallback;
+ }
+
+ /*
+ * TODO: This is a potential dangerous side channel. However, you can
+ * fix this by changing the RSA engine in a way, that it will always
+ * return blocks of the same length and prepend them with 0 bytes if
+ * needed.
+ */
+ if (block.length < getOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block truncated");
+ }
+
+ /*
+ * TODO: Potential side channel. Fix it by making the engine always
+ * return blocks of the correct length.
+ */
+ if (useStrictLength && block.length != engine.getOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block incorrect size");
+ }
+
+ /*
+ * Check the padding.
+ */
+ int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen);
+
+ /*
+ * Now, to a constant time constant memory copy of the decrypted value
+ * or the random value, depending on the validity of the padding.
+ */
+ byte[] result = new byte[this.pLen];
+ for (int i = 0; i < this.pLen; i++)
+ {
+ result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct));
+ }
+
+ return result;
+ }
/**
* @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
@@ -193,7 +346,15 @@ public class PKCS1Encoding
int inLen)
throws InvalidCipherTextException
{
- byte[] block = engine.processBlock(in, inOff, inLen);
+ /*
+ * If the length of the expected plaintext is known, we use a constant-time decryption.
+ * If the decryption fails, we return a random value.
+ */
+ if (this.pLen != -1) {
+ return this.decodeBlockOrRandom(in, inOff, inLen);
+ }
+
+ byte[] block = engine.processBlock(in, inOff, inLen);
if (block.length < getOutputBlockSize())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
index 756197c..a0fd084 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
@@ -473,74 +473,65 @@ private static final int[] Tinv0 =
private void encryptBlock(int[][] KW)
{
- int r, r0, r1, r2, r3;
-
- C0 ^= KW[0][0];
- C1 ^= KW[0][1];
- C2 ^= KW[0][2];
- C3 ^= KW[0][3];
-
- r = 1;
+ int t0 = this.C0 ^ KW[0][0];
+ int t1 = this.C1 ^ KW[0][1];
+ int t2 = this.C2 ^ KW[0][2];
+ int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3];
while (r < ROUNDS - 1)
{
- r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255],16) ^ shift(T0[(C3>>24)&255],8) ^ KW[r][0];
- r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
- r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
- r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
- C0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
- C1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1];
- C2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2];
- C3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3];
+ r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+ r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1];
+ r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2];
+ r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3];
+ t0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+ t1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1];
+ t2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2];
+ r3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3];
}
- r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255], 16) ^ shift(T0[(C3>>24)&255], 8) ^ KW[r][0];
- r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
- r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
- r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
+ r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+ r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1];
+ r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2];
+ r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
- C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
- C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
- C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
- C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
-
+ this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
+ this.C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
+ this.C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+ this.C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
}
private void decryptBlock(int[][] KW)
{
- int r, r0, r1, r2, r3;
-
- C0 ^= KW[ROUNDS][0];
- C1 ^= KW[ROUNDS][1];
- C2 ^= KW[ROUNDS][2];
- C3 ^= KW[ROUNDS][3];
-
- r = ROUNDS-1;
+ int t0 = this.C0 ^ KW[ROUNDS][0];
+ int t1 = this.C1 ^ KW[ROUNDS][1];
+ int t2 = this.C2 ^ KW[ROUNDS][2];
- while (r>1)
+ int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3];
+ while (r > 1)
{
- r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
- r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
- r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
- r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3];
- C0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0];
- C1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1];
- C2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
- C3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3];
+ r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0];
+ r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1];
+ r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+ r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r--][3];
+ t0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0];
+ t1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1];
+ t2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+ r3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3];
}
- r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
- r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
- r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
- r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r][3];
+ r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0];
+ r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1];
+ r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+ r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r][3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
- C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
- C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
- C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
- C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+ this.C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+ this.C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
+ this.C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
+ this.C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
index ff4b2f8..e2b00d3 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
@@ -5,6 +5,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.Pack;
/**
* an implementation of the AES (Rijndael), from FIPS-197.
@@ -110,8 +111,9 @@ public class AESFastEngine
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
// precomputation tables of calculations for rounds
- private static final int[] T0 =
+ private static final int[] T =
{
+ // T0
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
@@ -163,10 +165,9 @@ public class AESFastEngine
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
- 0x3a16162c};
+ 0x3a16162c,
- private static final int[] T1 =
- {
+ // T1
0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,
@@ -218,10 +219,9 @@ public class AESFastEngine
0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da,
0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0,
0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6,
- 0x16162c3a};
+ 0x16162c3a,
- private static final int[] T2 =
- {
+ // T2
0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,
@@ -273,10 +273,9 @@ public class AESFastEngine
0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf,
0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099,
0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb,
- 0x162c3a16};
+ 0x162c3a16,
- private static final int[] T3 =
- {
+ // T3
0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,
@@ -330,8 +329,9 @@ public class AESFastEngine
0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb,
0x2c3a1616};
- private static final int[] Tinv0 =
+ private static final int[] Tinv =
{
+ // Tinv0
0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
@@ -383,10 +383,9 @@ public class AESFastEngine
0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
- 0x4257b8d0};
+ 0x4257b8d0,
- private static final int[] Tinv1 =
- {
+ // Tinv1
0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,
@@ -438,10 +437,9 @@ public class AESFastEngine
0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672,
0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de,
0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874,
- 0x57b8d042};
+ 0x57b8d042,
- private static final int[] Tinv2 =
- {
+ // Tinv2
0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,
@@ -493,10 +491,9 @@ public class AESFastEngine
0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3,
0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3,
0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c,
- 0xb8d04257};
+ 0xb8d04257,
- private static final int[] Tinv3 =
- {
+ // Tinv3
0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,
@@ -586,10 +583,11 @@ public class AESFastEngine
return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
}
-
private static int subWord(int x)
{
- return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+ int i0 = x, i1 = x >>> 8, i2 = x >>> 16, i3 = x >>> 24;
+ i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+ return i0 | i1 << 8 | i2 << 16 | i3 << 24;
}
/**
@@ -727,19 +725,19 @@ public class AESFastEngine
throw new OutputLengthException("output buffer too short");
}
+ unpackBlock(in, inOff);
+
if (forEncryption)
{
- unpackBlock(in, inOff);
encryptBlock(WorkingKey);
- packBlock(out, outOff);
}
else
{
- unpackBlock(in, inOff);
decryptBlock(WorkingKey);
- packBlock(out, outOff);
}
+ packBlock(out, outOff);
+
return BLOCK_SIZE;
}
@@ -747,129 +745,184 @@ public class AESFastEngine
{
}
- private void unpackBlock(
- byte[] bytes,
- int off)
+ private void unpackBlock(byte[] bytes, int off)
{
- int index = off;
-
- C0 = (bytes[index++] & 0xff);
- C0 |= (bytes[index++] & 0xff) << 8;
- C0 |= (bytes[index++] & 0xff) << 16;
- C0 |= bytes[index++] << 24;
-
- C1 = (bytes[index++] & 0xff);
- C1 |= (bytes[index++] & 0xff) << 8;
- C1 |= (bytes[index++] & 0xff) << 16;
- C1 |= bytes[index++] << 24;
-
- C2 = (bytes[index++] & 0xff);
- C2 |= (bytes[index++] & 0xff) << 8;
- C2 |= (bytes[index++] & 0xff) << 16;
- C2 |= bytes[index++] << 24;
-
- C3 = (bytes[index++] & 0xff);
- C3 |= (bytes[index++] & 0xff) << 8;
- C3 |= (bytes[index++] & 0xff) << 16;
- C3 |= bytes[index++] << 24;
+ this.C0 = Pack.littleEndianToInt(bytes, off);
+ this.C1 = Pack.littleEndianToInt(bytes, off + 4);
+ this.C2 = Pack.littleEndianToInt(bytes, off + 8);
+ this.C3 = Pack.littleEndianToInt(bytes, off + 12);
}
- private void packBlock(
- byte[] bytes,
- int off)
+ private void packBlock(byte[] bytes, int off)
{
- int index = off;
-
- bytes[index++] = (byte)C0;
- bytes[index++] = (byte)(C0 >> 8);
- bytes[index++] = (byte)(C0 >> 16);
- bytes[index++] = (byte)(C0 >> 24);
-
- bytes[index++] = (byte)C1;
- bytes[index++] = (byte)(C1 >> 8);
- bytes[index++] = (byte)(C1 >> 16);
- bytes[index++] = (byte)(C1 >> 24);
-
- bytes[index++] = (byte)C2;
- bytes[index++] = (byte)(C2 >> 8);
- bytes[index++] = (byte)(C2 >> 16);
- bytes[index++] = (byte)(C2 >> 24);
-
- bytes[index++] = (byte)C3;
- bytes[index++] = (byte)(C3 >> 8);
- bytes[index++] = (byte)(C3 >> 16);
- bytes[index++] = (byte)(C3 >> 24);
+ Pack.intToLittleEndian(this.C0, bytes, off);
+ Pack.intToLittleEndian(this.C1, bytes, off + 4);
+ Pack.intToLittleEndian(this.C2, bytes, off + 8);
+ Pack.intToLittleEndian(this.C3, bytes, off + 12);
}
private void encryptBlock(int[][] KW)
{
- int r, r0, r1, r2, r3;
-
- C0 ^= KW[0][0];
- C1 ^= KW[0][1];
- C2 ^= KW[0][2];
- C3 ^= KW[0][3];
+ int t0 = this.C0 ^ KW[0][0];
+ int t1 = this.C1 ^ KW[0][1];
+ int t2 = this.C2 ^ KW[0][2];
+
+ /*
+ * Fast engine has precomputed rotr(T0, 8/16/24) tables T1/T2/T3.
+ *
+ * Placing all precomputes in one array requires offsets additions for 8/16/24 rotations but
+ * avoids additional array range checks on 3 more arrays (which on HotSpot are more
+ * expensive than the offset additions).
+ */
+ int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3];
+ int i0, i1, i2, i3;
- r = 1;
while (r < ROUNDS - 1)
{
- r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0];
- r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1];
- r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2];
- r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3];
- C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r][0];
- C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r][1];
- C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r][2];
- C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++][3];
+ i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+ i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+ i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+ i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
+
+ i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+ i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+ i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+ i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
}
- r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0];
- r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1];
- r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2];
- r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3];
-
+ i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+ i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+ i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+ i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
+
// the final round's table is a simple function of S so we don't use a whole other four tables for it
- C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
- C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
- C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
- C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+ i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24;
+ i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+ this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][0];
+
+ i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24;
+ i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+ this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][1];
+ i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24;
+ i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+ this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][2];
+
+ i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24;
+ i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+ this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][3];
}
private void decryptBlock(int[][] KW)
{
- int r0, r1, r2, r3;
+ int t0 = this.C0 ^ KW[ROUNDS][0];
+ int t1 = this.C1 ^ KW[ROUNDS][1];
+ int t2 = this.C2 ^ KW[ROUNDS][2];
- C0 ^= KW[ROUNDS][0];
- C1 ^= KW[ROUNDS][1];
- C2 ^= KW[ROUNDS][2];
- C3 ^= KW[ROUNDS][3];
+ int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3];
+ int i0, i1, i2, i3;
- int r = ROUNDS-1;
-
- while (r>1)
+ while (r > 1)
{
- r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0];
- r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1];
- r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2];
- r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--][3];
- C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r][0];
- C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r][1];
- C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r][2];
- C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--][3];
+ i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0];
+
+ i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1];
+
+ i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2];
+
+ i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3];
+
+ i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0];
+
+ i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1];
+
+ i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ t2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2];
+
+ i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3];
}
- r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0];
- r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1];
- r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2];
- r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r][3];
-
+ i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][0];
+
+ i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][1];
+
+ i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][2];
+
+ i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24;
+ i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+ r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][3];
+
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
- C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
- C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
- C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
- C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+ i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24;
+ i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+ this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][0];
+
+ i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24;
+ i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+ this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][1];
+
+ i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24;
+ i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+ this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][2];
+
+ i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24;
+ i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+ this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][3];
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
index 9b1e404..6980fd0 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
@@ -301,7 +301,7 @@ public class DESEngine
* generate an integer based working key based on our secret key
* and what we processing we are planning to do.
*
- * Acknowledgements for this routine go to James Gillogly & Phil Karn.
+ * Acknowledgements for this routine go to James Gillogly &amp; Phil Karn.
* (whoever, and wherever they are!).
*/
protected int[] generateWorkingKey(
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
index d0c04f2..197b151 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -62,8 +62,8 @@ public class DESedeWrapEngine
/**
* Method init
*
- * @param forWrapping
- * @param param
+ * @param forWrapping true if for wrapping, false otherwise.
+ * @param param necessary parameters, may include KeyParameter, ParametersWithRandom, and ParametersWithIV
*/
public void init(boolean forWrapping, CipherParameters param)
{
@@ -132,9 +132,9 @@ public class DESedeWrapEngine
/**
* Method wrap
*
- * @param in
- * @param inOff
- * @param inLen
+ * @param in byte array containing the encoded key.
+ * @param inOff off set into in that the data starts at.
+ * @param inLen length of the data.
* @return the wrapped bytes.
*/
public byte[] wrap(byte[] in, int inOff, int inLen)
@@ -203,9 +203,9 @@ public class DESedeWrapEngine
/**
* Method unwrap
*
- * @param in
- * @param inOff
- * @param inLen
+ * @param in byte array containing the wrapped key.
+ * @param inOff off set into in that the data starts at.
+ * @param inLen length of the data.
* @return the unwrapped bytes.
* @throws InvalidCipherTextException
*/
@@ -309,10 +309,11 @@ public class DESedeWrapEngine
* - Compute the 20 octet SHA-1 hash on the key being wrapped.
* - Use the first 8 octets of this hash as the checksum value.
*
- * @param key
+ * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum.
+ *
+ * @param key the key to check,
* @return the CMS checksum.
* @throws RuntimeException
- * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private byte[] calculateCMSKeyChecksum(
byte[] key)
@@ -328,10 +329,11 @@ public class DESedeWrapEngine
}
/**
- * @param key
- * @param checksum
+ * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ *
+ * @param key key to be validated.
+ * @param checksum the checksum.
* @return true if okay, false otherwise.
- * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
private boolean checkCMSKeyChecksum(
byte[] key,
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java
index 4de7ea6..c1ceaa4 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java
@@ -68,7 +68,7 @@ public class RC4Engine implements StreamCipher
return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
- public void processBytes(
+ public int processBytes(
byte[] in,
int inOff,
int len,
@@ -99,6 +99,8 @@ public class RC4Engine implements StreamCipher
out[i+outOff] = (byte)(in[i + inOff]
^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
+
+ return len;
}
public void reset()
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
index e0d86fc..6795ec9 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
@@ -4,6 +4,7 @@ import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.math.ec.WNafUtil;
import org.bouncycastle.util.BigIntegers;
class DHKeyGeneratorHelper
@@ -19,12 +20,19 @@ class DHKeyGeneratorHelper
BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random)
{
- BigInteger p = dhParams.getP();
int limit = dhParams.getL();
if (limit != 0)
{
- return new BigInteger(limit, random).setBit(limit - 1);
+ int minWeight = limit >>> 2;
+ for (;;)
+ {
+ BigInteger x = new BigInteger(limit, random).setBit(limit - 1);
+ if (WNafUtil.getNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
}
BigInteger min = TWO;
@@ -34,14 +42,22 @@ class DHKeyGeneratorHelper
min = ONE.shiftLeft(m - 1);
}
- BigInteger max = p.subtract(TWO);
BigInteger q = dhParams.getQ();
- if (q != null)
+ if (q == null)
{
- max = q.subtract(TWO);
+ q = dhParams.getP();
}
+ BigInteger max = q.subtract(TWO);
- return BigIntegers.createRandomInRange(min, max, random);
+ int minWeight = max.bitLength() >>> 2;
+ for (;;)
+ {
+ BigInteger x = BigIntegers.createRandomInRange(min, max, random);
+ if (WNafUtil.getNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
}
BigInteger calculatePublic(DHParameters dhParams, BigInteger x)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
index 05c7839..a0728b2 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
@@ -6,6 +6,7 @@ import java.security.SecureRandom;
// BEGIN android-added
import java.util.logging.Logger;
// END android-added
+import org.bouncycastle.math.ec.WNafUtil;
import org.bouncycastle.util.BigIntegers;
class DHParametersHelper
@@ -31,6 +32,7 @@ class DHParametersHelper
// END android-added
BigInteger p, q;
int qLength = size - 1;
+ int minWeight = size >>> 2;
for (;;)
{
@@ -42,10 +44,28 @@ class DHParametersHelper
// p <- 2q + 1
p = q.shiftLeft(1).add(ONE);
- if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty)))
+ if (!p.isProbablePrime(certainty))
{
- break;
+ continue;
}
+
+ if (certainty > 2 && !q.isProbablePrime(certainty - 2))
+ {
+ continue;
+ }
+
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight primes may be
+ * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtil.getNafWeight(p) < minWeight)
+ {
+ continue;
+ }
+
+ break;
}
// BEGIN android-added
long end = System.currentTimeMillis();
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
index 93f49cf..ff3df35 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.generators;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
@@ -7,11 +10,9 @@ import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.math.ec.WNafUtil;
import org.bouncycastle.util.BigIntegers;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
/**
* a DSA key pair generator.
*
@@ -45,13 +46,20 @@ public class DSAKeyPairGenerator
private static BigInteger generatePrivateKey(BigInteger q, SecureRandom random)
{
- // TODO Prefer this method? (change test cases that used fixed random)
- // B.1.1 Key Pair Generation Using Extra Random Bits
-// BigInteger c = new BigInteger(q.bitLength() + 64, random);
-// return c.mod(q.subtract(ONE)).add(ONE);
-
// B.1.2 Key Pair Generation by Testing Candidates
- return BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random);
+ int minWeight = q.bitLength() >>> 2;
+ for (;;)
+ {
+ // TODO Prefer this method? (change test cases that used fixed random)
+ // B.1.1 Key Pair Generation Using Extra Random Bits
+// BigInteger x = new BigInteger(q.bitLength() + 64, random).mod(q.subtract(ONE)).add(ONE);
+
+ BigInteger x = BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random);
+ if (WNafUtil.getNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
}
private static BigInteger calculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index d70ee8f..36b41cc 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -46,7 +46,7 @@ public class DSAParametersGenerator
/**
* initialise the key generator.
*
- * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+ * @param size size of the key (range 2^512 -&gt; 2^1024 - 64 bit increments)
* @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
* @param random random byte source.
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
index d5f5fc8..4f46a38 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -11,7 +11,10 @@ import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.FixedPointCombMultiplier;
+import org.bouncycastle.math.ec.WNafUtil;
public class ECKeyPairGenerator
implements AsymmetricCipherKeyPairGenerator, ECConstants
@@ -40,19 +43,42 @@ public class ECKeyPairGenerator
public AsymmetricCipherKeyPair generateKeyPair()
{
BigInteger n = params.getN();
- int nBitLength = n.bitLength();
- BigInteger d;
+ int nBitLength = n.bitLength();
+ int minWeight = nBitLength >>> 2;
- do
+ BigInteger d;
+ for (;;)
{
d = new BigInteger(nBitLength, random);
+
+ if (d.compareTo(TWO) < 0 || (d.compareTo(n) >= 0))
+ {
+ continue;
+ }
+
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight primes may be
+ * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtil.getNafWeight(d) < minWeight)
+ {
+ continue;
+ }
+
+ break;
}
- while (d.equals(ZERO) || (d.compareTo(n) >= 0));
- ECPoint Q = params.getG().multiply(d);
+ ECPoint Q = createBasePointMultiplier().multiply(params.getG(), d);
return new AsymmetricCipherKeyPair(
new ECPublicKeyParameters(Q, params),
new ECPrivateKeyParameters(d, params));
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
index f58069d..928c6a6 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
@@ -6,6 +6,7 @@ import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.math.ec.WNafUtil;
import java.math.BigInteger;
@@ -19,83 +20,43 @@ public class RSAKeyPairGenerator
private RSAKeyGenerationParameters param;
- public void init(
- KeyGenerationParameters param)
+ public void init(KeyGenerationParameters param)
{
this.param = (RSAKeyGenerationParameters)param;
}
public AsymmetricCipherKeyPair generateKeyPair()
{
- BigInteger p, q, n, d, e, pSub1, qSub1, phi;
+ BigInteger p, q, n, d, e, pSub1, qSub1, phi;
//
// p and q values should have a length of half the strength in bits
//
int strength = param.getStrength();
- int pbitlength = (strength + 1) / 2;
- int qbitlength = strength - pbitlength;
+ int qBitlength = strength >>> 1;
+ int pBitlength = strength - qBitlength;
int mindiffbits = strength / 3;
+ int minWeight = strength >>> 2;
e = param.getPublicExponent();
// TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
// (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
- //
- // generate p, prime and (p-1) relatively prime to e
- //
- for (;;)
- {
- p = new BigInteger(pbitlength, 1, param.getRandom());
-
- if (p.mod(e).equals(ONE))
- {
- continue;
- }
-
- if (!p.isProbablePrime(param.getCertainty()))
- {
- continue;
- }
-
- if (e.gcd(p.subtract(ONE)).equals(ONE))
- {
- break;
- }
- }
+ p = chooseRandomPrime(pBitlength, e);
//
// generate a modulus of the required length
//
for (;;)
{
- // generate q, prime and (q-1) relatively prime to e,
- // and not equal to p
- //
- for (;;)
+ q = chooseRandomPrime(qBitlength, e);
+
+ // p and q should not be too close together (or equal!)
+ BigInteger diff = q.subtract(p).abs();
+ if (diff.bitLength() < mindiffbits)
{
- q = new BigInteger(qbitlength, 1, param.getRandom());
-
- if (q.subtract(p).abs().bitLength() < mindiffbits)
- {
- continue;
- }
-
- if (q.mod(e).equals(ONE))
- {
- continue;
- }
-
- if (!q.isProbablePrime(param.getCertainty()))
- {
- continue;
- }
-
- if (e.gcd(q.subtract(ONE)).equals(ONE))
- {
- break;
- }
+ continue;
}
//
@@ -103,16 +64,29 @@ public class RSAKeyPairGenerator
//
n = p.multiply(q);
- if (n.bitLength() == param.getStrength())
+ if (n.bitLength() != strength)
{
- break;
+ //
+ // if we get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.max(q);
+ continue;
}
- //
- // if we get here our primes aren't big enough, make the largest
- // of the two p and try again
- //
- p = p.max(q);
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight composites may
+ * be weak against a version of the number-field-sieve for factoring.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtil.getNafWeight(n) < minWeight)
+ {
+ p = chooseRandomPrime(pBitlength, e);
+ continue;
+ }
+
+ break;
}
if (p.compareTo(q) < 0)
@@ -134,14 +108,46 @@ public class RSAKeyPairGenerator
//
// calculate the CRT factors
//
- BigInteger dP, dQ, qInv;
+ BigInteger dP, dQ, qInv;
dP = d.remainder(pSub1);
dQ = d.remainder(qSub1);
qInv = q.modInverse(p);
return new AsymmetricCipherKeyPair(
- new RSAKeyParameters(false, n, e),
- new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ new RSAKeyParameters(false, n, e),
+ new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+
+ /**
+ * Choose a random prime value for use with RSA
+ *
+ * @param bitlength the bit-length of the returned prime
+ * @param e the RSA public exponent
+ * @return a prime p, with (p-1) relatively prime to e
+ */
+ protected BigInteger chooseRandomPrime(int bitlength, BigInteger e)
+ {
+ for (;;)
+ {
+ BigInteger p = new BigInteger(bitlength, 1, param.getRandom());
+
+ if (p.mod(e).equals(ONE))
+ {
+ continue;
+ }
+
+ if (!p.isProbablePrime(param.getCertainty()))
+ {
+ continue;
+ }
+
+ if (!e.gcd(p.subtract(ONE)).equals(ONE))
+ {
+ continue;
+ }
+
+ return p;
+ }
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
index 71b7595..fe46119 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
@@ -7,6 +7,16 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
/**
* A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * <p>
+ * Implementations of this interface may operate in a packet mode (where all input data is buffered and
+ * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is
+ * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or
+ * {@link #processBytes(byte[], int, int, byte[], int)}.
+ * </p>
+ * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data
+ * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication
+ * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled
+ * appropriately until the end of data is reached and the entire ciphertext is authenticated.
* @see org.bouncycastle.crypto.params.AEADParameters
*/
public interface AEADBlockCipher
@@ -101,6 +111,11 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes
* an input of len bytes.
+ * <p>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to input data being processed.
+ * </p>
*
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes
@@ -111,7 +126,12 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes plus a
* doFinal with an input of len bytes.
- *
+ * <p>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to a call to final processing of input data
+ * and a call to {@link #doFinal(byte[], int)}.
+ * </p>
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes and doFinal
* with len bytes of input.
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
index fef51fd..7f870ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -7,6 +7,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -42,7 +43,7 @@ public class CCMBlockCipher
this.cipher = c;
this.blockSize = c.getBlockSize();
this.macBlock = new byte[blockSize];
-
+
if (blockSize != 16)
{
throw new IllegalArgumentException("cipher required with a block size of 16.");
@@ -99,7 +100,7 @@ public class CCMBlockCipher
{
throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
}
-
+
reset();
}
@@ -130,6 +131,10 @@ public class CCMBlockCipher
public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
throws DataLengthException, IllegalStateException
{
+ if (in.length < (inOff + inLen))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
data.write(in, inOff, inLen);
return 0;
@@ -155,15 +160,15 @@ public class CCMBlockCipher
/**
* Returns a byte array containing the mac calculated as part of the
* last encrypt or decrypt operation.
- *
+ *
* @return the last mac calculated.
*/
public byte[] getMac()
{
byte[] mac = new byte[macSize];
-
+
System.arraycopy(macBlock, 0, mac, 0, mac.length);
-
+
return mac;
}
@@ -267,7 +272,7 @@ public class CCMBlockCipher
outputLen = inLen + macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
calculateMac(in, inOff, inLen, macBlock);
@@ -300,7 +305,7 @@ public class CCMBlockCipher
outputLen = inLen - macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize);
@@ -350,18 +355,18 @@ public class CCMBlockCipher
// build b0
//
byte[] b0 = new byte[16];
-
+
if (hasAssociatedText())
{
b0[0] |= 0x40;
}
-
+
b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
b0[0] |= ((15 - nonce.length) - 1) & 0x7;
-
+
System.arraycopy(nonce, 0, b0, 1, nonce.length);
-
+
int q = dataLen;
int count = 1;
while (q > 0)
@@ -370,22 +375,22 @@ public class CCMBlockCipher
q >>>= 8;
count++;
}
-
+
cMac.update(b0, 0, b0.length);
-
+
//
// process associated text
//
if (hasAssociatedText())
{
int extra;
-
+
int textLength = getAssociatedTextLength();
if (textLength < ((1 << 16) - (1 << 8)))
{
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 2;
}
else // can't go any higher than 2^32
@@ -396,7 +401,7 @@ public class CCMBlockCipher
cMac.update((byte)(textLength >> 16));
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 6;
}
@@ -418,7 +423,7 @@ public class CCMBlockCipher
}
}
}
-
+
//
// add the text
//
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
index a885169..6167d25 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -3,6 +3,7 @@ package org.bouncycastle.crypto.modes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
@@ -10,15 +11,17 @@ import org.bouncycastle.util.Arrays;
* implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
*/
public class CFBBlockCipher
- implements BlockCipher
+ extends StreamBlockCipher
{
private byte[] IV;
private byte[] cfbV;
private byte[] cfbOutV;
+ private byte[] inBuf;
private int blockSize;
private BlockCipher cipher = null;
private boolean encrypting;
+ private int byteCount;
/**
* Basic constructor.
@@ -31,22 +34,15 @@ public class CFBBlockCipher
BlockCipher cipher,
int bitBlockSize)
{
+ super(cipher);
+
this.cipher = cipher;
this.blockSize = bitBlockSize / 8;
this.IV = new byte[cipher.getBlockSize()];
this.cfbV = new byte[cipher.getBlockSize()];
this.cfbOutV = new byte[cipher.getBlockSize()];
- }
-
- /**
- * return the underlying block cipher that we are wrapping.
- *
- * @return the underlying block cipher that we are wrapping.
- */
- public BlockCipher getUnderlyingCipher()
- {
- return cipher;
+ this.inBuf = new byte[blockSize];
}
/**
@@ -117,6 +113,54 @@ public class CFBBlockCipher
return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
}
+ protected byte calculateByte(byte in)
+ throws DataLengthException, IllegalStateException
+ {
+ return (encrypting) ? encryptByte(in) : decryptByte(in);
+ }
+
+ private byte encryptByte(byte in)
+ {
+ if (byteCount == 0)
+ {
+ cipher.processBlock(cfbV, 0, cfbOutV, 0);
+ }
+
+ byte rv = (byte)(cfbOutV[byteCount] ^ in);
+ inBuf[byteCount++] = rv;
+
+ if (byteCount == blockSize)
+ {
+ byteCount = 0;
+
+ System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+ System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize);
+ }
+
+ return rv;
+ }
+
+ private byte decryptByte(byte in)
+ {
+ if (byteCount == 0)
+ {
+ cipher.processBlock(cfbV, 0, cfbOutV, 0);
+ }
+
+ inBuf[byteCount] = in;
+ byte rv = (byte)(cfbOutV[byteCount++] ^ in);
+
+ if (byteCount == blockSize)
+ {
+ byteCount = 0;
+
+ System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+ System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize);
+ }
+
+ return rv;
+ }
+
/**
* return the block size we are operating at.
*
@@ -147,7 +191,9 @@ public class CFBBlockCipher
int outOff)
throws DataLengthException, IllegalStateException
{
- return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ processBytes(in, inOff, blockSize, out, outOff);
+
+ return blockSize;
}
/**
@@ -169,31 +215,7 @@ public class CFBBlockCipher
int outOff)
throws DataLengthException, IllegalStateException
{
- if ((inOff + blockSize) > in.length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + blockSize) > out.length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- cipher.processBlock(cfbV, 0, cfbOutV, 0);
-
- //
- // XOR the cfbV with the plaintext producing the ciphertext
- //
- for (int i = 0; i < blockSize; i++)
- {
- out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
- }
-
- //
- // change over the input block.
- //
- System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
- System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
+ processBytes(in, inOff, blockSize, out, outOff);
return blockSize;
}
@@ -217,31 +239,7 @@ public class CFBBlockCipher
int outOff)
throws DataLengthException, IllegalStateException
{
- if ((inOff + blockSize) > in.length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + blockSize) > out.length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- cipher.processBlock(cfbV, 0, cfbOutV, 0);
-
- //
- // change over the input block.
- //
- System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
- System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize);
-
- //
- // XOR the cfbV with the ciphertext producing the plaintext
- //
- for (int i = 0; i < blockSize; i++)
- {
- out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
- }
+ processBytes(in, inOff, blockSize, out, outOff);
return blockSize;
}
@@ -263,6 +261,8 @@ public class CFBBlockCipher
public void reset()
{
System.arraycopy(IV, 0, cfbV, 0, IV.length);
+ Arrays.fill(inBuf, (byte)0);
+ byteCount = 0;
cipher.reset();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index 9e617ec..024eb86 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
import org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator;
@@ -11,8 +12,8 @@ import org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
/**
* Implements the Galois/Counter mode (GCM) detailed in
@@ -23,7 +24,7 @@ public class GCMBlockCipher
{
private static final int BLOCK_SIZE = 16;
- // not final due to a compiler bug
+ // not final due to a compiler bug
private BlockCipher cipher;
private GCMMultiplier multiplier;
private GCMExponentiator exp;
@@ -81,6 +82,10 @@ public class GCMBlockCipher
return cipher.getAlgorithmName() + "/GCM";
}
+ /**
+ * NOTE: MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
+ * Sizes less than 96 are not recommended, but are supported for specialized applications.
+ */
public void init(boolean forEncryption, CipherParameters params)
throws IllegalArgumentException
{
@@ -97,12 +102,12 @@ public class GCMBlockCipher
initialAssociatedText = param.getAssociatedText();
int macSizeBits = param.getMacSize();
- if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
{
throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
}
- macSize = macSizeBits / 8;
+ macSize = macSizeBits / 8;
keyParam = param.getKey();
}
else if (params instanceof ParametersWithIV)
@@ -119,7 +124,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("invalid parameters passed to GCM");
}
- int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
this.bufBlock = new byte[bufLength];
if (nonce == null || nonce.length < 1)
@@ -127,9 +132,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("IV must be at least 1 byte");
}
- // TODO This should be configurable by init parameters
- // (but must be 16 if nonce length not 12) (BLOCK_SIZE?)
-// this.tagLength = 16;
+ // TODO Restrict macSize to 16 if nonce length not 12?
// Cipher always used in forward mode
// if keyParam is null we're reusing the last key.
@@ -144,6 +147,10 @@ public class GCMBlockCipher
multiplier.init(H);
exp = null;
}
+ else if (this.H == null)
+ {
+ throw new IllegalArgumentException("Key must be specified in initial init");
+ }
this.J0 = new byte[BLOCK_SIZE];
@@ -188,7 +195,7 @@ public class GCMBlockCipher
if (forEncryption)
{
- return totalData + macSize;
+ return totalData + macSize;
}
return totalData < macSize ? 0 : totalData - macSize;
@@ -271,6 +278,10 @@ public class GCMBlockCipher
public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
throws DataLengthException
{
+ if (in.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -288,6 +299,10 @@ public class GCMBlockCipher
private void outputBlock(byte[] output, int offset)
{
+ if (output.length < (offset + BLOCK_SIZE))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
if (totalLength == 0)
{
initCipher();
@@ -324,6 +339,10 @@ public class GCMBlockCipher
if (extra > 0)
{
+ if (out.length < (outOff + extra))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
gCTRPartial(bufBlock, 0, extra, out, outOff);
}
@@ -376,7 +395,6 @@ public class GCMBlockCipher
gHASHBlock(S, X);
- // TODO Fix this if tagLength becomes configurable
// T = MSBt(GCTRk(J0,S))
byte[] tag = new byte[BLOCK_SIZE];
cipher.processBlock(J0, 0, tag, 0);
@@ -390,6 +408,10 @@ public class GCMBlockCipher
if (forEncryption)
{
+ if (out.length < (outOff + extra + macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
// Append T to the message
System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
resultLen += macSize;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
index 5297698..d9ff428 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
@@ -3,14 +3,16 @@ package org.bouncycastle.crypto.modes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
/**
* implements a Output-FeedBack (OFB) mode on top of a simple cipher.
*/
public class OFBBlockCipher
- implements BlockCipher
+ extends StreamBlockCipher
{
+ private int byteCount;
private byte[] IV;
private byte[] ofbV;
private byte[] ofbOutV;
@@ -29,6 +31,8 @@ public class OFBBlockCipher
BlockCipher cipher,
int blockSize)
{
+ super(cipher);
+
this.cipher = cipher;
this.blockSize = blockSize / 8;
@@ -38,16 +42,6 @@ public class OFBBlockCipher
}
/**
- * return the underlying block cipher that we are wrapping.
- *
- * @return the underlying block cipher that we are wrapping.
- */
- public BlockCipher getUnderlyingCipher()
- {
- return cipher;
- }
-
- /**
* Initialise the cipher and, possibly, the initialisation vector (IV).
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
* An IV which is too short is handled in FIPS compliant fashion.
@@ -113,7 +107,7 @@ public class OFBBlockCipher
return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
}
-
+
/**
* return the block size we are operating at (in bytes).
*
@@ -144,32 +138,7 @@ public class OFBBlockCipher
int outOff)
throws DataLengthException, IllegalStateException
{
- if ((inOff + blockSize) > in.length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + blockSize) > out.length)
- {
- throw new DataLengthException("output buffer too short");
- }
-
- cipher.processBlock(ofbV, 0, ofbOutV, 0);
-
- //
- // XOR the ofbV with the plaintext producing the cipher text (and
- // the next input block).
- //
- for (int i = 0; i < blockSize; i++)
- {
- out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
- }
-
- //
- // change over the input block.
- //
- System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
- System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+ processBytes(in, inOff, blockSize, out, outOff);
return blockSize;
}
@@ -181,7 +150,29 @@ public class OFBBlockCipher
public void reset()
{
System.arraycopy(IV, 0, ofbV, 0, IV.length);
+ byteCount = 0;
cipher.reset();
}
+
+ protected byte calculateByte(byte in)
+ throws DataLengthException, IllegalStateException
+ {
+ if (byteCount == 0)
+ {
+ cipher.processBlock(ofbV, 0, ofbOutV, 0);
+ }
+
+ byte rv = (byte)(ofbOutV[byteCount++] ^ in);
+
+ if (byteCount == blockSize)
+ {
+ byteCount = 0;
+
+ System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+ System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+ }
+
+ return rv;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
index da8c4ae..5dd47ae 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -3,14 +3,18 @@ package org.bouncycastle.crypto.modes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.SkippingStreamCipher;
+import org.bouncycastle.crypto.StreamBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Pack;
/**
* Implements the Segmented Integer Counter (SIC) mode on top of a simple
* block cipher. This mode is also known as CTR mode.
*/
public class SICBlockCipher
- implements BlockCipher
+ extends StreamBlockCipher
+ implements SkippingStreamCipher
{
private final BlockCipher cipher;
private final int blockSize;
@@ -18,7 +22,7 @@ public class SICBlockCipher
private byte[] IV;
private byte[] counter;
private byte[] counterOut;
-
+ private int byteCount;
/**
* Basic constructor.
@@ -27,25 +31,16 @@ public class SICBlockCipher
*/
public SICBlockCipher(BlockCipher c)
{
+ super(c);
+
this.cipher = c;
this.blockSize = cipher.getBlockSize();
this.IV = new byte[blockSize];
this.counter = new byte[blockSize];
this.counterOut = new byte[blockSize];
+ this.byteCount = 0;
}
-
- /**
- * return the underlying block cipher that we are wrapping.
- *
- * @return the underlying block cipher that we are wrapping.
- */
- public BlockCipher getUnderlyingCipher()
- {
- return cipher;
- }
-
-
public void init(
boolean forEncryption, //ignored by this CTR mode
CipherParameters params)
@@ -53,17 +48,17 @@ public class SICBlockCipher
{
if (params instanceof ParametersWithIV)
{
- ParametersWithIV ivParam = (ParametersWithIV)params;
- byte[] iv = ivParam.getIV();
- System.arraycopy(iv, 0, IV, 0, IV.length);
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+ System.arraycopy(iv, 0, IV, 0, IV.length);
- reset();
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
- // if null it's an IV changed only.
- if (ivParam.getParameters() != null)
- {
- cipher.init(true, ivParam.getParameters());
- }
+ reset();
}
else
{
@@ -81,33 +76,150 @@ public class SICBlockCipher
return cipher.getBlockSize();
}
-
public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
throws DataLengthException, IllegalStateException
{
- cipher.processBlock(counter, 0, counterOut, 0);
+ processBytes(in, inOff, blockSize, out, outOff);
- //
- // XOR the counterOut with the plaintext producing the cipher text
- //
- for (int i = 0; i < counterOut.length; i++)
+ return blockSize;
+ }
+
+ protected byte calculateByte(byte in)
+ throws DataLengthException, IllegalStateException
+ {
+ if (byteCount == 0)
{
- out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]);
+ cipher.processBlock(counter, 0, counterOut, 0);
+
+ return (byte)(counterOut[byteCount++] ^ in);
+ }
+
+ byte rv = (byte)(counterOut[byteCount++] ^ in);
+
+ if (byteCount == counter.length)
+ {
+ byteCount = 0;
+
+ incrementCounter();
}
+ return rv;
+ }
+
+ private void incrementCounter()
+ {
// increment counter by 1.
for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--)
{
; // do nothing - pre-increment and test for 0 in counter does the job.
}
+ }
- return counter.length;
+ private void decrementCounter()
+ {
+ if (counter[0] == 0)
+ {
+ boolean nonZero = false;
+
+ for (int i = counter.length - 1; i > 0; i--)
+ {
+ if (counter[i] != 0)
+ {
+ nonZero = true;
+ }
+ }
+
+ if (!nonZero)
+ {
+ throw new IllegalStateException("attempt to reduce counter past zero.");
+ }
+ }
+
+ // decrement counter by 1.
+ for (int i = counter.length - 1; i >= 0 && --counter[i] == -1; i--)
+ {
+ ;
+ }
}
+ private void adjustCounter(long n)
+ {
+ if (n >= 0)
+ {
+ long numBlocks = (n + byteCount) / blockSize;
+
+ for (long i = 0; i != numBlocks; i++)
+ {
+ incrementCounter();
+ }
+
+ byteCount = (int)((n + byteCount) - (blockSize * numBlocks));
+ }
+ else
+ {
+ long numBlocks = (-n - byteCount) / blockSize;
+
+ for (long i = 0; i != numBlocks; i++)
+ {
+ decrementCounter();
+ }
+
+ int gap = (int)(byteCount + n + (blockSize * numBlocks));
+
+ if (gap >= 0)
+ {
+ byteCount = 0;
+ }
+ else
+ {
+ decrementCounter();
+ byteCount = blockSize + gap;
+ }
+ }
+ }
public void reset()
{
System.arraycopy(IV, 0, counter, 0, counter.length);
cipher.reset();
+ this.byteCount = 0;
+ }
+
+ public long skip(long numberOfBytes)
+ {
+ adjustCounter(numberOfBytes);
+
+ cipher.processBlock(counter, 0, counterOut, 0);
+
+ return numberOfBytes;
+ }
+
+ public long seekTo(long position)
+ {
+ reset();
+
+ return skip(position);
+ }
+
+ public long getPosition()
+ {
+ byte[] res = new byte[IV.length];
+
+ System.arraycopy(counter, 0, res, 0, res.length);
+
+ for (int i = res.length - 1; i >= 1; i--)
+ {
+ int v = (res[i] - IV[i]);
+
+ if (v < 0)
+ {
+ res[i - 1]--;
+ v += 256;
+ }
+
+ res[i] = (byte)v;
+ }
+
+ return Pack.bigEndianToLong(res, res.length - 8) * blockSize + byteCount;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
index 3031a44..f5ed7e4 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.modes.gcm;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
abstract class GCMUtil
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
index 8535db5..69c1dce 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
@@ -1,7 +1,7 @@
package org.bouncycastle.crypto.modes.gcm;
-import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
public class Tables8kGCMMultiplier implements GCMMultiplier
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
index ee3fd60..d5928f7 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -125,7 +125,7 @@ public class PaddedBufferedBlockCipher
if (leftOver == 0)
{
- return total - buf.length;
+ return Math.max(0, total - buf.length);
}
return total - leftOver;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java
new file mode 100644
index 0000000..5b694be
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECNamedDomainParameters
+ extends ECDomainParameters
+{
+ private ASN1ObjectIdentifier name;
+
+ public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n)
+ {
+ this(name, curve, G, n, null, null);
+ }
+
+ public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h)
+ {
+ this(name, curve, G, n, h, null);
+ }
+
+ public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h, byte[] seed)
+ {
+ super(curve, G, n, h, seed);
+
+ this.name = name;
+ }
+
+ public ASN1ObjectIdentifier getName()
+ {
+ return name;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
index 292c408..f3614f3 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
@@ -45,18 +45,19 @@ public class DSASigner
boolean forSigning,
CipherParameters param)
{
+ SecureRandom providedRandom = null;
+
if (forSigning)
{
if (param instanceof ParametersWithRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
- this.random = rParam.getRandom();
this.key = (DSAPrivateKeyParameters)rParam.getParameters();
+ providedRandom = rParam.getRandom();
}
else
{
- this.random = new SecureRandom();
this.key = (DSAPrivateKeyParameters)param;
}
}
@@ -64,6 +65,8 @@ public class DSASigner
{
this.key = (DSAPublicKeyParameters)param;
}
+
+ this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom);
}
/**
@@ -157,4 +160,9 @@ public class DSASigner
return new BigInteger(1, trunc);
}
}
+
+ protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
+ {
+ return !needed ? null : (provided != null) ? provided : new SecureRandom();
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
index 2a1f98e..5fce112 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -5,13 +5,16 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.FixedPointCombMultiplier;
/**
* EC-DSA as described in X9.62
@@ -46,18 +49,19 @@ public class ECDSASigner
boolean forSigning,
CipherParameters param)
{
+ SecureRandom providedRandom = null;
+
if (forSigning)
{
if (param instanceof ParametersWithRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
- this.random = rParam.getRandom();
this.key = (ECPrivateKeyParameters)rParam.getParameters();
+ providedRandom = rParam.getRandom();
}
else
{
- this.random = new SecureRandom();
this.key = (ECPrivateKeyParameters)param;
}
}
@@ -65,6 +69,8 @@ public class ECDSASigner
{
this.key = (ECPublicKeyParameters)param;
}
+
+ this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom);
}
// 5.3 pg 28
@@ -78,50 +84,44 @@ public class ECDSASigner
public BigInteger[] generateSignature(
byte[] message)
{
- BigInteger n = key.getParameters().getN();
+ ECDomainParameters ec = key.getParameters();
+ BigInteger n = ec.getN();
BigInteger e = calculateE(n, message);
- BigInteger r = null;
- BigInteger s = null;
+ BigInteger d = ((ECPrivateKeyParameters)key).getD();
if (kCalculator.isDeterministic())
{
- kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message);
+ kCalculator.init(n, d, message);
}
else
{
kCalculator.init(n, random);
}
+ BigInteger r, s;
+
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
+
// 5.3.2
do // generate s
{
- BigInteger k = null;
-
+ BigInteger k;
do // generate r
{
k = kCalculator.nextK();
- ECPoint p = key.getParameters().getG().multiply(k).normalize();
+ ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize();
// 5.3.3
- BigInteger x = p.getAffineXCoord().toBigInteger();
-
- r = x.mod(n);
+ r = p.getAffineXCoord().toBigInteger().mod(n);
}
while (r.equals(ZERO));
- BigInteger d = ((ECPrivateKeyParameters)key).getD();
-
s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
}
while (s.equals(ZERO));
- BigInteger[] res = new BigInteger[2];
-
- res[0] = r;
- res[1] = s;
-
- return res;
+ return new BigInteger[]{ r, s };
}
// 5.4 pg 29
@@ -135,7 +135,8 @@ public class ECDSASigner
BigInteger r,
BigInteger s)
{
- BigInteger n = key.getParameters().getN();
+ ECDomainParameters ec = key.getParameters();
+ BigInteger n = ec.getN();
BigInteger e = calculateE(n, message);
// r in the range [1,n-1]
@@ -155,7 +156,7 @@ public class ECDSASigner
BigInteger u1 = e.multiply(c).mod(n);
BigInteger u2 = r.multiply(c).mod(n);
- ECPoint G = key.getParameters().getG();
+ ECPoint G = ec.getG();
ECPoint Q = ((ECPublicKeyParameters)key).getQ();
ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize();
@@ -171,7 +172,7 @@ public class ECDSASigner
return v.equals(r);
}
- private BigInteger calculateE(BigInteger n, byte[] message)
+ protected BigInteger calculateE(BigInteger n, byte[] message)
{
int log2n = n.bitLength();
int messageBitLength = message.length * 8;
@@ -183,4 +184,14 @@ public class ECDSASigner
}
return e;
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+
+ protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
+ {
+ return !needed ? null : (provided != null) ? provided : new SecureRandom();
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
index 18dd84e..2a32278 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -50,6 +50,8 @@ public class RSADigestSigner
oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+ oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224);
+ oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256);
// BEGIN android-removed
// oidMap.put("MD2", PKCSObjectIdentifiers.md2);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java
index f0da0bf..2ded8ef 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.util;
+/**
+ * @deprecated use org.bouncycastle.util.pack
+ */
public abstract class Pack
{
public static int bigEndianToInt(byte[] bs, int off)
@@ -114,6 +117,15 @@ public abstract class Pack
}
}
+ public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ ns[nOff + i] = littleEndianToInt(bs, bOff);
+ bOff += 4;
+ }
+ }
+
public static byte[] intToLittleEndian(int n)
{
byte[] bs = new byte[4];
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index d997db7..0175aa1 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
// BEGIN android-removed
// import org.bouncycastle.asn1.oiw.ElGamalParameter;
// END android-removed
@@ -25,12 +24,14 @@ import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
// BEGIN android-removed
// import org.bouncycastle.crypto.params.ElGamalParameters;
@@ -104,8 +105,8 @@ public class PrivateKeyFactory
// BEGIN android-removed
// else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
// {
- // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
- // ASN1Integer = (ASN1Integer)keyInfo.parsePrivateKey();
+ // ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
+ // ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
//
// return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
// params.getP(), params.getG()));
@@ -130,24 +131,30 @@ public class PrivateKeyFactory
X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters());
X9ECParameters x9;
+ ECDomainParameters dParams;
+
if (params.isNamedCurve())
{
- ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
- x9 = ECNamedCurveTable.getByOID(oid);
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+
+ x9 = CustomNamedCurves.getByOID(oid);
+ if (x9 == null)
+ {
+ x9 = ECNamedCurveTable.getByOID(oid);
+ }
+ dParams = new ECNamedDomainParameters(
+ oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
}
else
{
x9 = X9ECParameters.getInstance(params.getParameters());
+ dParams = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
}
ECPrivateKey ec = ECPrivateKey.getInstance(keyInfo.parsePrivateKey());
BigInteger d = ec.getKey();
- // TODO We lose any named parameters here
-
- ECDomainParameters dParams = new ECDomainParameters(
- x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
-
return new ECPrivateKeyParameters(d, dParams);
}
else
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index 7ade197..2b33321 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -10,7 +10,6 @@ import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
// BEGIN android-removed
// import org.bouncycastle.asn1.oiw.ElGamalParameter;
@@ -31,6 +30,7 @@ import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
@@ -38,6 +38,7 @@ import org.bouncycastle.crypto.params.DHValidationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
// BEGIN android-removed
// import org.bouncycastle.crypto.params.ElGamalParameters;
@@ -139,7 +140,7 @@ public class PublicKeyFactory
// BEGIN android-removed
// else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
// {
- // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ // ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
// ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
//
// return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
@@ -166,24 +167,30 @@ public class PublicKeyFactory
X962Parameters params = X962Parameters.getInstance(algId.getParameters());
X9ECParameters x9;
+ ECDomainParameters dParams;
+
if (params.isNamedCurve())
{
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
- x9 = ECNamedCurveTable.getByOID(oid);
+
+ x9 = CustomNamedCurves.getByOID(oid);
+ if (x9 == null)
+ {
+ x9 = ECNamedCurveTable.getByOID(oid);
+ }
+ dParams = new ECNamedDomainParameters(
+ oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
}
else
{
x9 = X9ECParameters.getInstance(params.getParameters());
+ dParams = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
}
ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key);
- // TODO We lose any named parameters here
-
- ECDomainParameters dParams = new ECDomainParameters(
- x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
-
return new ECPublicKeyParameters(derQ.getPoint(), dParams);
}
else