Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-05-20 10:53:37 +0400
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-05-20 10:53:37 +0400
commit0f73e910b43507924c95c319116c49818aff1532 (patch)
treec509468b2e272cc91b6c4b1465bddb6c0fec1787
parentfa5b8d7b38278fd9da92a71f6c47987e12da0507 (diff)
parent01a4148cbb7db83113bd6b45528e413d0b1d40cc (diff)
Merge branch 'master' into tls
-rw-r--r--src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java84
-rw-r--r--src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java850
-rw-r--r--src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java264
-rw-r--r--src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java782
-rw-r--r--src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java92
-rw-r--r--src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java370
-rw-r--r--src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java180
-rw-r--r--src/main/java/org/bouncycastle/bcpg/UserIDPacket.java78
-rw-r--r--src/main/java/org/bouncycastle/cert/CertRuntimeException.java19
-rw-r--r--src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java2
-rw-r--r--src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java4
-rw-r--r--src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java5
-rw-r--r--src/main/java/org/bouncycastle/cms/RecipientInformationStore.java236
-rwxr-xr-xsrc/main/java/org/bouncycastle/crypto/KeyEncapsulation.java22
-rw-r--r--src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java262
-rw-r--r--src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java148
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/GOST3411Digest.java47
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java9
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/LongDigest.java9
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java23
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/NonMemoableDigest.java64
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/RIPEMD128Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/RIPEMD160Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/RIPEMD256Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/RIPEMD320Digest.java20
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java19
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java21
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java14
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java13
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java38
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/TigerDigest.java37
-rw-r--r--src/main/java/org/bouncycastle/crypto/digests/WhirlpoolDigest.java41
-rw-r--r--src/main/java/org/bouncycastle/crypto/ec/ECPair.java13
-rw-r--r--src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java28
-rwxr-xr-xsrc/main/java/org/bouncycastle/crypto/engines/IESEngine.java796
-rw-r--r--src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java284
-rw-r--r--src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java172
-rwxr-xr-xsrc/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java254
-rwxr-xr-xsrc/main/java/org/bouncycastle/crypto/kems/RSAKeyEncapsulation.java161
-rw-r--r--src/main/java/org/bouncycastle/crypto/macs/GMac.java108
-rw-r--r--src/main/java/org/bouncycastle/crypto/macs/HMac.java38
-rw-r--r--src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java756
-rw-r--r--src/main/java/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java80
-rw-r--r--src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java15
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java5
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/DRBGProvider.java8
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/EntropySource.java17
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/SP80090DRBG.java9
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandom.java (renamed from src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java)12
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java (renamed from src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java)27
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/VMPCRandomGenerator.java1
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java (renamed from src/main/java/org/bouncycastle/crypto/prng/CTRSP800DRBG.java)220
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java (renamed from src/main/java/org/bouncycastle/crypto/prng/DualECSP800DRBG.java)168
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java (renamed from src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java)64
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java (renamed from src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java)574
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java25
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java103
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/package.html5
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/package.html2
-rw-r--r--src/main/java/org/bouncycastle/crypto/random/DRBGProvider.java9
-rw-r--r--src/main/java/org/bouncycastle/crypto/util/Pack.java384
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java2
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java47
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java14
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java18
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java2
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java17
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java17
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java7
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java21
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java16
-rw-r--r--src/main/java/org/bouncycastle/math/ec/ECPoint.java1186
-rw-r--r--src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java96
-rw-r--r--src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java38
-rw-r--r--src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyEncryptor.java15
-rw-r--r--src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyEncryptorBuilder.java34
-rw-r--r--src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyEncryptorBuilder.java42
-rw-r--r--src/main/java/org/bouncycastle/util/Arrays.java10
-rw-r--r--src/main/java/org/bouncycastle/util/Memoable.java23
-rw-r--r--src/main/java/org/bouncycastle/util/MemoableResetException.java22
-rw-r--r--src/main/java/org/bouncycastle/util/encoders/Base64.java302
-rw-r--r--src/main/java/org/bouncycastle/util/encoders/Hex.java296
-rw-r--r--src/test/java/org/bouncycastle/cert/ocsp/test/OCSPTest.java30
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java39
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java513
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java (renamed from src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java)2
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java)53
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java)24
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java)37
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java (renamed from src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java)6
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java (renamed from src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java)22
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java (renamed from src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java)7
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java190
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/DSATest.java508
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/DigestTest.java40
-rwxr-xr-xsrc/test/java/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java138
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/GMacTest.java170
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/NonMemoableDigestTest.java112
-rwxr-xr-xsrc/test/java/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java61
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/RegressionTest.java8
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java82
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java46
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/DSATest.java143
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java145
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java49
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java1
-rw-r--r--src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java163
-rw-r--r--src/test/java/org/bouncycastle/openpgp/test/PGPNoPrivateKeyTest.java167
-rw-r--r--src/test/java/org/bouncycastle/openpgp/test/PGPRSATest.java10
-rw-r--r--src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java3
118 files changed, 8606 insertions, 4685 deletions
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index 4d6df7a3..98f46a6d 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -1,42 +1,42 @@
-package org.bouncycastle.asn1;
-
-public class ASN1ObjectIdentifier
- extends DERObjectIdentifier
-{
- public ASN1ObjectIdentifier(String identifier)
- {
- super(identifier);
- }
-
- ASN1ObjectIdentifier(byte[] bytes)
- {
- super(bytes);
- }
-
- ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
- {
- super(oid, branch);
- }
-
- /**
- * Return an OID that creates a branch under the current one.
- *
- * @param branchID node numbers for the new branch.
- * @return the OID for the new created branch.
- */
- public ASN1ObjectIdentifier branch(String branchID)
- {
- return new ASN1ObjectIdentifier(this, branchID);
- }
-
- /**
- * Return true if this oid is an extension of the passed in branch, stem.
- * @param stem the arc or branch that is a possible parent.
- * @return true if the branch is on the passed in stem, false otherwise.
- */
- public boolean on(ASN1ObjectIdentifier stem)
- {
- String id = getId(), stemId = stem.getId();
- return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
- }
-}
+package org.bouncycastle.asn1;
+
+public class ASN1ObjectIdentifier
+ extends DERObjectIdentifier
+{
+ public ASN1ObjectIdentifier(String identifier)
+ {
+ super(identifier);
+ }
+
+ ASN1ObjectIdentifier(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
+ {
+ super(oid, branch);
+ }
+
+ /**
+ * Return an OID that creates a branch under the current one.
+ *
+ * @param branchID node numbers for the new branch.
+ * @return the OID for the new created branch.
+ */
+ public ASN1ObjectIdentifier branch(String branchID)
+ {
+ return new ASN1ObjectIdentifier(this, branchID);
+ }
+
+ /**
+ * Return true if this oid is an extension of the passed in branch, stem.
+ * @param stem the arc or branch that is a possible parent.
+ * @return true if the branch is on the passed in stem, false otherwise.
+ */
+ public boolean on(ASN1ObjectIdentifier stem)
+ {
+ String id = getId(), stemId = stem.getId();
+ return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
index 4f320b30..418f991b 100644
--- a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -1,425 +1,425 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.util.Arrays;
-
-public class DERObjectIdentifier
- extends ASN1Primitive
-{
- String identifier;
-
- private byte[] body;
-
- /**
- * return an OID from the passed in object
- *
- * @exception IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1ObjectIdentifier getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)obj;
- }
-
- if (obj instanceof DERObjectIdentifier)
- {
- return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
- }
-
- if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
- }
-
- if (obj instanceof byte[])
- {
- return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
- /**
- * return an Object Identifier from a tagged object.
- *
- * @param obj the tagged object holding the object we want
- * @param explicit true if the object is meant to be explicitly
- * tagged false otherwise.
- * @exception IllegalArgumentException if the tagged object cannot
- * be converted.
- */
- public static ASN1ObjectIdentifier getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DERObjectIdentifier)
- {
- return getInstance(o);
- }
- else
- {
- return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
- }
- }
-
- private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
-
- DERObjectIdentifier(
- byte[] bytes)
- {
- StringBuffer objId = new StringBuffer();
- long value = 0;
- BigInteger bigValue = null;
- boolean first = true;
-
- for (int i = 0; i != bytes.length; i++)
- {
- int b = bytes[i] & 0xff;
-
- if (value <= LONG_LIMIT)
- {
- value += (b & 0x7f);
- if ((b & 0x80) == 0) // end of number reached
- {
- if (first)
- {
- if (value < 40)
- {
- objId.append('0');
- }
- else if (value < 80)
- {
- objId.append('1');
- value -= 40;
- }
- else
- {
- objId.append('2');
- value -= 80;
- }
- first = false;
- }
-
- objId.append('.');
- objId.append(value);
- value = 0;
- }
- else
- {
- value <<= 7;
- }
- }
- else
- {
- if (bigValue == null)
- {
- bigValue = BigInteger.valueOf(value);
- }
- bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
- if ((b & 0x80) == 0)
- {
- if (first)
- {
- objId.append('2');
- bigValue = bigValue.subtract(BigInteger.valueOf(80));
- first = false;
- }
-
- objId.append('.');
- objId.append(bigValue);
- bigValue = null;
- value = 0;
- }
- else
- {
- bigValue = bigValue.shiftLeft(7);
- }
- }
- }
-
- this.identifier = objId.toString();
- this.body = Arrays.clone(bytes);
- }
-
- public DERObjectIdentifier(
- String identifier)
- {
- if (identifier == null)
- {
- throw new IllegalArgumentException("'identifier' cannot be null");
- }
- if (!isValidIdentifier(identifier))
- {
- throw new IllegalArgumentException("string " + identifier + " not an OID");
- }
-
- this.identifier = identifier;
- }
-
- DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
- {
- if (!isValidBranchID(branchID, 0))
- {
- throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
- }
-
- this.identifier = oid.getId() + "." + branchID;
- }
-
- public String getId()
- {
- return identifier;
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- long fieldValue)
- {
- byte[] result = new byte[9];
- int pos = 8;
- result[pos] = (byte)((int)fieldValue & 0x7f);
- while (fieldValue >= (1L << 7))
- {
- fieldValue >>= 7;
- result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
- }
- out.write(result, pos, 9 - pos);
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- BigInteger fieldValue)
- {
- int byteCount = (fieldValue.bitLength()+6)/7;
- if (byteCount == 0)
- {
- out.write(0);
- }
- else
- {
- BigInteger tmpValue = fieldValue;
- byte[] tmp = new byte[byteCount];
- for (int i = byteCount-1; i >= 0; i--)
- {
- tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
- tmpValue = tmpValue.shiftRight(7);
- }
- tmp[byteCount-1] &= 0x7f;
- out.write(tmp, 0, tmp.length);
- }
- }
-
- private void doOutput(ByteArrayOutputStream aOut)
- {
- OIDTokenizer tok = new OIDTokenizer(identifier);
- int first = Integer.parseInt(tok.nextToken()) * 40;
-
- String secondToken = tok.nextToken();
- if (secondToken.length() <= 18)
- {
- writeField(aOut, first + Long.parseLong(secondToken));
- }
- else
- {
- writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
- }
-
- while (tok.hasMoreTokens())
- {
- String token = tok.nextToken();
- if (token.length() <= 18)
- {
- writeField(aOut, Long.parseLong(token));
- }
- else
- {
- writeField(aOut, new BigInteger(token));
- }
- }
- }
-
- protected synchronized byte[] getBody()
- {
- if (body == null)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- doOutput(bOut);
-
- body = bOut.toByteArray();
- }
-
- return body;
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
- throws IOException
- {
- int length = getBody().length;
-
- return 1 + StreamUtil.calculateBodyLength(length) + length;
- }
-
- void encode(
- ASN1OutputStream out)
- throws IOException
- {
- byte[] enc = getBody();
-
- out.write(BERTags.OBJECT_IDENTIFIER);
- out.writeLength(enc.length);
- out.write(enc);
- }
-
- public int hashCode()
- {
- return identifier.hashCode();
- }
-
- boolean asn1Equals(
- ASN1Primitive o)
- {
- if (!(o instanceof DERObjectIdentifier))
- {
- return false;
- }
-
- return identifier.equals(((DERObjectIdentifier)o).identifier);
- }
-
- public String toString()
- {
- return getId();
- }
-
- private static boolean isValidBranchID(
- String branchID, int start)
- {
- boolean periodAllowed = false;
-
- int pos = branchID.length();
- while (--pos >= start)
- {
- char ch = branchID.charAt(pos);
-
- // TODO Leading zeroes?
- if ('0' <= ch && ch <= '9')
- {
- periodAllowed = true;
- continue;
- }
-
- if (ch == '.')
- {
- if (!periodAllowed)
- {
- return false;
- }
-
- periodAllowed = false;
- continue;
- }
-
- return false;
- }
-
- return periodAllowed;
- }
-
- private static boolean isValidIdentifier(
- String identifier)
- {
- if (identifier.length() < 3 || identifier.charAt(1) != '.')
- {
- return false;
- }
-
- char first = identifier.charAt(0);
- if (first < '0' || first > '2')
- {
- return false;
- }
-
- return isValidBranchID(identifier, 2);
- }
-
- private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
-
- static ASN1ObjectIdentifier fromOctetString(byte[] enc)
- {
- if (enc.length < 3)
- {
- return new ASN1ObjectIdentifier(enc);
- }
-
- int idx1 = enc[enc.length - 2] & 0xff;
- // in this case top bit is always zero
- int idx2 = enc[enc.length - 1] & 0x7f;
-
- ASN1ObjectIdentifier possibleMatch;
-
- synchronized (cache)
- {
- ASN1ObjectIdentifier[] first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx1 = (idx1 + 1) & 0xff;
- first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx2 = (idx2 + 1) & 0x7f;
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- return new ASN1ObjectIdentifier(enc);
- }
-}
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.util.Arrays;
+
+public class DERObjectIdentifier
+ extends ASN1Primitive
+{
+ String identifier;
+
+ private byte[] body;
+
+ /**
+ * return an OID from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1ObjectIdentifier getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1ObjectIdentifier)
+ {
+ return (ASN1ObjectIdentifier)obj;
+ }
+
+ if (obj instanceof DERObjectIdentifier)
+ {
+ return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
+ }
+
+ if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
+ {
+ return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
+ }
+
+ if (obj instanceof byte[])
+ {
+ return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Object Identifier from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1ObjectIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERObjectIdentifier)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+ }
+ }
+
+ private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
+
+ DERObjectIdentifier(
+ byte[] bytes)
+ {
+ StringBuffer objId = new StringBuffer();
+ long value = 0;
+ BigInteger bigValue = null;
+ boolean first = true;
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ int b = bytes[i] & 0xff;
+
+ if (value <= LONG_LIMIT)
+ {
+ value += (b & 0x7f);
+ if ((b & 0x80) == 0) // end of number reached
+ {
+ if (first)
+ {
+ if (value < 40)
+ {
+ objId.append('0');
+ }
+ else if (value < 80)
+ {
+ objId.append('1');
+ value -= 40;
+ }
+ else
+ {
+ objId.append('2');
+ value -= 80;
+ }
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(value);
+ value = 0;
+ }
+ else
+ {
+ value <<= 7;
+ }
+ }
+ else
+ {
+ if (bigValue == null)
+ {
+ bigValue = BigInteger.valueOf(value);
+ }
+ bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+ if ((b & 0x80) == 0)
+ {
+ if (first)
+ {
+ objId.append('2');
+ bigValue = bigValue.subtract(BigInteger.valueOf(80));
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(bigValue);
+ bigValue = null;
+ value = 0;
+ }
+ else
+ {
+ bigValue = bigValue.shiftLeft(7);
+ }
+ }
+ }
+
+ this.identifier = objId.toString();
+ this.body = Arrays.clone(bytes);
+ }
+
+ public DERObjectIdentifier(
+ String identifier)
+ {
+ if (identifier == null)
+ {
+ throw new IllegalArgumentException("'identifier' cannot be null");
+ }
+ if (!isValidIdentifier(identifier))
+ {
+ throw new IllegalArgumentException("string " + identifier + " not an OID");
+ }
+
+ this.identifier = identifier;
+ }
+
+ DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
+ {
+ if (!isValidBranchID(branchID, 0))
+ {
+ throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
+ }
+
+ this.identifier = oid.getId() + "." + branchID;
+ }
+
+ public String getId()
+ {
+ return identifier;
+ }
+
+ private void writeField(
+ ByteArrayOutputStream out,
+ long fieldValue)
+ {
+ byte[] result = new byte[9];
+ int pos = 8;
+ result[pos] = (byte)((int)fieldValue & 0x7f);
+ while (fieldValue >= (1L << 7))
+ {
+ fieldValue >>= 7;
+ result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
+ }
+ out.write(result, pos, 9 - pos);
+ }
+
+ private void writeField(
+ ByteArrayOutputStream out,
+ BigInteger fieldValue)
+ {
+ int byteCount = (fieldValue.bitLength()+6)/7;
+ if (byteCount == 0)
+ {
+ out.write(0);
+ }
+ else
+ {
+ BigInteger tmpValue = fieldValue;
+ byte[] tmp = new byte[byteCount];
+ for (int i = byteCount-1; i >= 0; i--)
+ {
+ tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
+ tmpValue = tmpValue.shiftRight(7);
+ }
+ tmp[byteCount-1] &= 0x7f;
+ out.write(tmp, 0, tmp.length);
+ }
+ }
+
+ private void doOutput(ByteArrayOutputStream aOut)
+ {
+ OIDTokenizer tok = new OIDTokenizer(identifier);
+ int first = Integer.parseInt(tok.nextToken()) * 40;
+
+ String secondToken = tok.nextToken();
+ if (secondToken.length() <= 18)
+ {
+ writeField(aOut, first + Long.parseLong(secondToken));
+ }
+ else
+ {
+ writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
+ }
+
+ while (tok.hasMoreTokens())
+ {
+ String token = tok.nextToken();
+ if (token.length() <= 18)
+ {
+ writeField(aOut, Long.parseLong(token));
+ }
+ else
+ {
+ writeField(aOut, new BigInteger(token));
+ }
+ }
+ }
+
+ protected synchronized byte[] getBody()
+ {
+ if (body == null)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ doOutput(bOut);
+
+ body = bOut.toByteArray();
+ }
+
+ return body;
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBody().length;
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ byte[] enc = getBody();
+
+ out.write(BERTags.OBJECT_IDENTIFIER);
+ out.writeLength(enc.length);
+ out.write(enc);
+ }
+
+ public int hashCode()
+ {
+ return identifier.hashCode();
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERObjectIdentifier))
+ {
+ return false;
+ }
+
+ return identifier.equals(((DERObjectIdentifier)o).identifier);
+ }
+
+ public String toString()
+ {
+ return getId();
+ }
+
+ private static boolean isValidBranchID(
+ String branchID, int start)
+ {
+ boolean periodAllowed = false;
+
+ int pos = branchID.length();
+ while (--pos >= start)
+ {
+ char ch = branchID.charAt(pos);
+
+ // TODO Leading zeroes?
+ if ('0' <= ch && ch <= '9')
+ {
+ periodAllowed = true;
+ continue;
+ }
+
+ if (ch == '.')
+ {
+ if (!periodAllowed)
+ {
+ return false;
+ }
+
+ periodAllowed = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return periodAllowed;
+ }
+
+ private static boolean isValidIdentifier(
+ String identifier)
+ {
+ if (identifier.length() < 3 || identifier.charAt(1) != '.')
+ {
+ return false;
+ }
+
+ char first = identifier.charAt(0);
+ if (first < '0' || first > '2')
+ {
+ return false;
+ }
+
+ return isValidBranchID(identifier, 2);
+ }
+
+ private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
+
+ static ASN1ObjectIdentifier fromOctetString(byte[] enc)
+ {
+ if (enc.length < 3)
+ {
+ return new ASN1ObjectIdentifier(enc);
+ }
+
+ int idx1 = enc[enc.length - 2] & 0xff;
+ // in this case top bit is always zero
+ int idx2 = enc[enc.length - 1] & 0x7f;
+
+ ASN1ObjectIdentifier possibleMatch;
+
+ synchronized (cache)
+ {
+ ASN1ObjectIdentifier[] first = cache[idx1];
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[128];
+ }
+
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ idx1 = (idx1 + 1) & 0xff;
+ first = cache[idx1];
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[128];
+ }
+
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ idx2 = (idx2 + 1) & 0x7f;
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ return new ASN1ObjectIdentifier(enc);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
index c604d4a8..f005cfa8 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -1,132 +1,132 @@
-package org.bouncycastle.asn1.x9;
-
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-
-public interface X9ObjectIdentifiers
-{
- //
- // X9.62
- //
- // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- // us(840) ansi-x962(10045) }
- //
- static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
- static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
-
- static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
-
- static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
-
- static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
-
- static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
-
- static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
-
- static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1");
-
- static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
-
- static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
-
- static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
-
- //
- // named curves
- //
- static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
-
- //
- // Two Curves
- //
- static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0");
-
- static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
- static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
- static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
- static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
- static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
- static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
- static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
- static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
- static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
- static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
- static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
- static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
- static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
- static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
- static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
- static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
- static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
- static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
- static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
- static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
-
- //
- // Prime
- //
- static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
-
- static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
- static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
- static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
- static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
- static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
- static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
- static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7");
-
- //
- // DSA
- //
- // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- // us(840) ansi-x957(10040) number-type(4) 1 }
- static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1");
-
- /**
- * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57
- * (10040) x9cm(4) 3 }
- */
- public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
-
- /**
- * X9.63
- */
- public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
- public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2");
- public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
- public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16");
-
- /**
- * X9.42
- */
-
- static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
-
- //
- // Diffie-Hellman
- //
- // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- // us(840) ansi-x942(10046) number-type(2) 1 }
- //
- public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
-
- public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
- public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1");
- public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2");
- public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3");
- public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4");
- public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5");
- public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
- public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7");
- public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8");
-}
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface X9ObjectIdentifiers
+{
+ //
+ // X9.62
+ //
+ // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x962(10045) }
+ //
+ static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+ static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
+
+ static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
+
+ static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
+
+ static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
+
+ static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
+
+ static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
+
+ static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1");
+
+ static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
+
+ static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
+
+ //
+ // named curves
+ //
+ static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
+
+ //
+ // Two Curves
+ //
+ static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0");
+
+ static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
+ static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
+ static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
+ static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
+ static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
+ static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
+ static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
+ static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
+ static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
+ static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
+ static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
+ static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
+ static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
+ static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
+ static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
+ static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
+ static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
+ static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
+ static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
+ static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
+
+ //
+ // Prime
+ //
+ static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
+
+ static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
+ static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
+ static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
+ static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
+ static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
+ static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
+ static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7");
+
+ //
+ // DSA
+ //
+ // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x957(10040) number-type(4) 1 }
+ static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1");
+
+ /**
+ * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57
+ * (10040) x9cm(4) 3 }
+ */
+ public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
+
+ /**
+ * X9.63
+ */
+ public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
+ public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2");
+ public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
+ public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16");
+
+ /**
+ * X9.42
+ */
+
+ static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
+
+ //
+ // Diffie-Hellman
+ //
+ // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x942(10046) number-type(2) 1 }
+ //
+ public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
+
+ public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
+ public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1");
+ public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2");
+ public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3");
+ public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4");
+ public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5");
+ public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
+ public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7");
+ public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8");
+}
diff --git a/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java b/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
index 86873cec..1e2e0723 100644
--- a/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
+++ b/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
@@ -1,391 +1,391 @@
-package org.bouncycastle.bcpg;
-
-import org.bouncycastle.util.io.Streams;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * reader for PGP objects
- */
-public class BCPGInputStream
- extends InputStream implements PacketTags
-{
- InputStream in;
- boolean next = false;
- int nextB;
-
- public BCPGInputStream(
- InputStream in)
- {
- this.in = in;
- }
-
- public int available()
- throws IOException
- {
- return in.available();
- }
-
- public int read()
- throws IOException
- {
- if (next)
- {
- next = false;
-
- return nextB;
- }
- else
- {
- return in.read();
- }
- }
-
- public int read(
- byte[] buf,
- int off,
- int len)
- throws IOException
- {
- if (len == 0)
- {
- return 0;
- }
-
- if (!next)
- {
- return in.read(buf, off, len);
- }
-
- // We have next byte waiting, so return it
-
- if (nextB < 0)
- {
- return -1; // EOF
- }
-
- buf[off] = (byte)nextB; // May throw NullPointerException...
- next = false; // ...so only set this afterwards
-
- return 1;
- }
-
- public void readFully(
- byte[] buf,
- int off,
- int len)
- throws IOException
- {
- if (Streams.readFully(this, buf, off, len) < len)
- {
- throw new EOFException();
- }
- }
-
- public byte[] readAll()
- throws IOException
- {
- return Streams.readAll(this);
- }
-
- public void readFully(
- byte[] buf)
- throws IOException
- {
- readFully(buf, 0, buf.length);
- }
-
- /**
- * returns the next packet tag in the stream.
- *
- * @return the tag number.
- *
- * @throws IOException
- */
- public int nextPacketTag()
- throws IOException
- {
- if (!next)
- {
- try
- {
- nextB = in.read();
- }
- catch (EOFException e)
- {
- nextB = -1;
- }
- }
-
- next = true;
-
- if (nextB >= 0)
- {
- if ((nextB & 0x40) != 0) // new
- {
- return (nextB & 0x3f);
- }
- else // old
- {
- return ((nextB & 0x3f) >> 2);
- }
- }
-
- return nextB;
- }
-
- public Packet readPacket()
- throws IOException
- {
- int hdr = this.read();
-
- if (hdr < 0)
- {
- return null;
- }
-
- if ((hdr & 0x80) == 0)
- {
- throw new IOException("invalid header encountered");
- }
-
- boolean newPacket = (hdr & 0x40) != 0;
- int tag = 0;
- int bodyLen = 0;
- boolean partial = false;
-
- if (newPacket)
- {
- tag = hdr & 0x3f;
-
- int l = this.read();
-
- if (l < 192)
- {
- bodyLen = l;
- }
- else if (l <= 223)
- {
- int b = in.read();
-
- bodyLen = ((l - 192) << 8) + (b) + 192;
- }
- else if (l == 255)
- {
- bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
- }
- else
- {
- partial = true;
- bodyLen = 1 << (l & 0x1f);
- }
- }
- else
- {
- int lengthType = hdr & 0x3;
-
- tag = (hdr & 0x3f) >> 2;
-
- switch (lengthType)
- {
- case 0:
- bodyLen = this.read();
- break;
- case 1:
- bodyLen = (this.read() << 8) | this.read();
- break;
- case 2:
- bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read();
- break;
- case 3:
- partial = true;
- break;
- default:
- throw new IOException("unknown length type encountered");
- }
- }
-
- BCPGInputStream objStream;
-
- if (bodyLen == 0 && partial)
- {
- objStream = this;
- }
- else
- {
- objStream = new BCPGInputStream(new PartialInputStream(this, partial, bodyLen));
- }
-
- switch (tag)
- {
- case RESERVED:
- return new InputStreamPacket(objStream);
- case PUBLIC_KEY_ENC_SESSION:
- return new PublicKeyEncSessionPacket(objStream);
- case SIGNATURE:
- return new SignaturePacket(objStream);
- case SYMMETRIC_KEY_ENC_SESSION:
- return new SymmetricKeyEncSessionPacket(objStream);
- case ONE_PASS_SIGNATURE:
- return new OnePassSignaturePacket(objStream);
- case SECRET_KEY:
- return new SecretKeyPacket(objStream);
- case PUBLIC_KEY:
- return new PublicKeyPacket(objStream);
- case SECRET_SUBKEY:
- return new SecretSubkeyPacket(objStream);
- case COMPRESSED_DATA:
- return new CompressedDataPacket(objStream);
- case SYMMETRIC_KEY_ENC:
- return new SymmetricEncDataPacket(objStream);
- case MARKER:
- return new MarkerPacket(objStream);
- case LITERAL_DATA:
- return new LiteralDataPacket(objStream);
- case TRUST:
- return new TrustPacket(objStream);
- case USER_ID:
- return new UserIDPacket(objStream);
- case USER_ATTRIBUTE:
- return new UserAttributePacket(objStream);
- case PUBLIC_SUBKEY:
- return new PublicSubkeyPacket(objStream);
- case SYM_ENC_INTEGRITY_PRO:
- return new SymmetricEncIntegrityPacket(objStream);
- case MOD_DETECTION_CODE:
- return new ModDetectionCodePacket(objStream);
- case EXPERIMENTAL_1:
- case EXPERIMENTAL_2:
- case EXPERIMENTAL_3:
- case EXPERIMENTAL_4:
- return new ExperimentalPacket(tag, objStream);
- default:
- throw new IOException("unknown packet type encountered: " + tag);
- }
- }
-
- public void close()
- throws IOException
- {
- in.close();
- }
-
- /**
- * a stream that overlays our input stream, allowing the user to only read a segment of it.
- *
- * NB: dataLength will be negative if the segment length is in the upper range above 2**31.
- */
- private static class PartialInputStream
- extends InputStream
- {
- private BCPGInputStream in;
- private boolean partial;
- private int dataLength;
-
- PartialInputStream(
- BCPGInputStream in,
- boolean partial,
- int dataLength)
- {
- this.in = in;
- this.partial = partial;
- this.dataLength = dataLength;
- }
-
- public int available()
- throws IOException
- {
- int avail = in.available();
-
- if (avail <= dataLength || dataLength < 0)
- {
- return avail;
- }
- else
- {
- if (partial && dataLength == 0)
- {
- return 1;
- }
- return dataLength;
- }
- }
-
- private int loadDataLength()
- throws IOException
- {
- int l = in.read();
-
- if (l < 0)
- {
- return -1;
- }
-
- partial = false;
- if (l < 192)
- {
- dataLength = l;
- }
- else if (l <= 223)
- {
- dataLength = ((l - 192) << 8) + (in.read()) + 192;
- }
- else if (l == 255)
- {
- dataLength = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
- }
- else
- {
- partial = true;
- dataLength = 1 << (l & 0x1f);
- }
-
- return dataLength;
- }
-
- public int read(byte[] buf, int offset, int len)
- throws IOException
- {
- do
- {
- if (dataLength != 0)
- {
- int readLen = (dataLength > len || dataLength < 0) ? len : dataLength;
- readLen = in.read(buf, offset, readLen);
- if (readLen < 0)
- {
- throw new EOFException("premature end of stream in PartialInputStream");
- }
- dataLength -= readLen;
- return readLen;
- }
- }
- while (partial && loadDataLength() >= 0);
-
- return -1;
- }
-
- public int read()
- throws IOException
- {
- do
- {
- if (dataLength != 0)
- {
- int ch = in.read();
- if (ch < 0)
- {
- throw new EOFException("premature end of stream in PartialInputStream");
- }
- dataLength--;
- return ch;
- }
- }
- while (partial && loadDataLength() >= 0);
-
- return -1;
- }
- }
-}
+package org.bouncycastle.bcpg;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.io.Streams;
+
+/**
+ * reader for PGP objects
+ */
+public class BCPGInputStream
+ extends InputStream implements PacketTags
+{
+ InputStream in;
+ boolean next = false;
+ int nextB;
+
+ public BCPGInputStream(
+ InputStream in)
+ {
+ this.in = in;
+ }
+
+ public int available()
+ throws IOException
+ {
+ return in.available();
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (next)
+ {
+ next = false;
+
+ return nextB;
+ }
+ else
+ {
+ return in.read();
+ }
+ }
+
+ public int read(
+ byte[] buf,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (len == 0)
+ {
+ return 0;
+ }
+
+ if (!next)
+ {
+ return in.read(buf, off, len);
+ }
+
+ // We have next byte waiting, so return it
+
+ if (nextB < 0)
+ {
+ return -1; // EOF
+ }
+
+ buf[off] = (byte)nextB; // May throw NullPointerException...
+ next = false; // ...so only set this afterwards
+
+ return 1;
+ }
+
+ public void readFully(
+ byte[] buf,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (Streams.readFully(this, buf, off, len) < len)
+ {
+ throw new EOFException();
+ }
+ }
+
+ public byte[] readAll()
+ throws IOException
+ {
+ return Streams.readAll(this);
+ }
+
+ public void readFully(
+ byte[] buf)
+ throws IOException
+ {
+ readFully(buf, 0, buf.length);
+ }
+
+ /**
+ * returns the next packet tag in the stream.
+ *
+ * @return the tag number.
+ *
+ * @throws IOException
+ */
+ public int nextPacketTag()
+ throws IOException
+ {
+ if (!next)
+ {
+ try
+ {
+ nextB = in.read();
+ }
+ catch (EOFException e)
+ {
+ nextB = -1;
+ }
+ }
+
+ next = true;
+
+ if (nextB >= 0)
+ {
+ if ((nextB & 0x40) != 0) // new
+ {
+ return (nextB & 0x3f);
+ }
+ else // old
+ {
+ return ((nextB & 0x3f) >> 2);
+ }
+ }
+
+ return nextB;
+ }
+
+ public Packet readPacket()
+ throws IOException
+ {
+ int hdr = this.read();
+
+ if (hdr < 0)
+ {
+ return null;
+ }
+
+ if ((hdr & 0x80) == 0)
+ {
+ throw new IOException("invalid header encountered");
+ }
+
+ boolean newPacket = (hdr & 0x40) != 0;
+ int tag = 0;
+ int bodyLen = 0;
+ boolean partial = false;
+
+ if (newPacket)
+ {
+ tag = hdr & 0x3f;
+
+ int l = this.read();
+
+ if (l < 192)
+ {
+ bodyLen = l;
+ }
+ else if (l <= 223)
+ {
+ int b = in.read();
+
+ bodyLen = ((l - 192) << 8) + (b) + 192;
+ }
+ else if (l == 255)
+ {
+ bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
+ }
+ else
+ {
+ partial = true;
+ bodyLen = 1 << (l & 0x1f);
+ }
+ }
+ else
+ {
+ int lengthType = hdr & 0x3;
+
+ tag = (hdr & 0x3f) >> 2;
+
+ switch (lengthType)
+ {
+ case 0:
+ bodyLen = this.read();
+ break;
+ case 1:
+ bodyLen = (this.read() << 8) | this.read();
+ break;
+ case 2:
+ bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read();
+ break;
+ case 3:
+ partial = true;
+ break;
+ default:
+ throw new IOException("unknown length type encountered");
+ }
+ }
+
+ BCPGInputStream objStream;
+
+ if (bodyLen == 0 && partial)
+ {
+ objStream = this;
+ }
+ else
+ {
+ objStream = new BCPGInputStream(new PartialInputStream(this, partial, bodyLen));
+ }
+
+ switch (tag)
+ {
+ case RESERVED:
+ return new InputStreamPacket(objStream);
+ case PUBLIC_KEY_ENC_SESSION:
+ return new PublicKeyEncSessionPacket(objStream);
+ case SIGNATURE:
+ return new SignaturePacket(objStream);
+ case SYMMETRIC_KEY_ENC_SESSION:
+ return new SymmetricKeyEncSessionPacket(objStream);
+ case ONE_PASS_SIGNATURE:
+ return new OnePassSignaturePacket(objStream);
+ case SECRET_KEY:
+ return new SecretKeyPacket(objStream);
+ case PUBLIC_KEY:
+ return new PublicKeyPacket(objStream);
+ case SECRET_SUBKEY:
+ return new SecretSubkeyPacket(objStream);
+ case COMPRESSED_DATA:
+ return new CompressedDataPacket(objStream);
+ case SYMMETRIC_KEY_ENC:
+ return new SymmetricEncDataPacket(objStream);
+ case MARKER:
+ return new MarkerPacket(objStream);
+ case LITERAL_DATA:
+ return new LiteralDataPacket(objStream);
+ case TRUST:
+ return new TrustPacket(objStream);
+ case USER_ID:
+ return new UserIDPacket(objStream);
+ case USER_ATTRIBUTE:
+ return new UserAttributePacket(objStream);
+ case PUBLIC_SUBKEY:
+ return new PublicSubkeyPacket(objStream);
+ case SYM_ENC_INTEGRITY_PRO:
+ return new SymmetricEncIntegrityPacket(objStream);
+ case MOD_DETECTION_CODE:
+ return new ModDetectionCodePacket(objStream);
+ case EXPERIMENTAL_1:
+ case EXPERIMENTAL_2:
+ case EXPERIMENTAL_3:
+ case EXPERIMENTAL_4:
+ return new ExperimentalPacket(tag, objStream);
+ default:
+ throw new IOException("unknown packet type encountered: " + tag);
+ }
+ }
+
+ public void close()
+ throws IOException
+ {
+ in.close();
+ }
+
+ /**
+ * a stream that overlays our input stream, allowing the user to only read a segment of it.
+ *
+ * NB: dataLength will be negative if the segment length is in the upper range above 2**31.
+ */
+ private static class PartialInputStream
+ extends InputStream
+ {
+ private BCPGInputStream in;
+ private boolean partial;
+ private int dataLength;
+
+ PartialInputStream(
+ BCPGInputStream in,
+ boolean partial,
+ int dataLength)
+ {
+ this.in = in;
+ this.partial = partial;
+ this.dataLength = dataLength;
+ }
+
+ public int available()
+ throws IOException
+ {
+ int avail = in.available();
+
+ if (avail <= dataLength || dataLength < 0)
+ {
+ return avail;
+ }
+ else
+ {
+ if (partial && dataLength == 0)
+ {
+ return 1;
+ }
+ return dataLength;
+ }
+ }
+
+ private int loadDataLength()
+ throws IOException
+ {
+ int l = in.read();
+
+ if (l < 0)
+ {
+ return -1;
+ }
+
+ partial = false;
+ if (l < 192)
+ {
+ dataLength = l;
+ }
+ else if (l <= 223)
+ {
+ dataLength = ((l - 192) << 8) + (in.read()) + 192;
+ }
+ else if (l == 255)
+ {
+ dataLength = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
+ }
+ else
+ {
+ partial = true;
+ dataLength = 1 << (l & 0x1f);
+ }
+
+ return dataLength;
+ }
+
+ public int read(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ do
+ {
+ if (dataLength != 0)
+ {
+ int readLen = (dataLength > len || dataLength < 0) ? len : dataLength;
+ readLen = in.read(buf, offset, readLen);
+ if (readLen < 0)
+ {
+ throw new EOFException("premature end of stream in PartialInputStream");
+ }
+ dataLength -= readLen;
+ return readLen;
+ }
+ }
+ while (partial && loadDataLength() >= 0);
+
+ return -1;
+ }
+
+ public int read()
+ throws IOException
+ {
+ do
+ {
+ if (dataLength != 0)
+ {
+ int ch = in.read();
+ if (ch < 0)
+ {
+ throw new EOFException("premature end of stream in PartialInputStream");
+ }
+ dataLength--;
+ return ch;
+ }
+ }
+ while (partial && loadDataLength() >= 0);
+
+ return -1;
+ }
+ }
+}
diff --git a/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java b/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
index e3b0456a..8407052b 100644
--- a/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
+++ b/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
@@ -1,46 +1,46 @@
-package org.bouncycastle.bcpg;
-
-import java.io.IOException;
-
-import org.bouncycastle.util.Arrays;
-
-/**
- * basic packet for an experimental packet.
- */
-public class ExperimentalPacket
- extends ContainedPacket implements PublicKeyAlgorithmTags
-{
- private int tag;
- private byte[] contents;
-
- /**
- *
- * @param in
- * @throws IOException
- */
- ExperimentalPacket(
- int tag,
- BCPGInputStream in)
- throws IOException
- {
- this.tag = tag;
- this.contents = in.readAll();
- }
-
- public int getTag()
- {
- return tag;
- }
-
- public byte[] getContents()
- {
- return Arrays.clone(contents);
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(tag, contents, true);
- }
-}
+package org.bouncycastle.bcpg;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * basic packet for an experimental packet.
+ */
+public class ExperimentalPacket
+ extends ContainedPacket implements PublicKeyAlgorithmTags
+{
+ private int tag;
+ private byte[] contents;
+
+ /**
+ *
+ * @param in
+ * @throws IOException
+ */
+ ExperimentalPacket(
+ int tag,
+ BCPGInputStream in)
+ throws IOException
+ {
+ this.tag = tag;
+ this.contents = in.readAll();
+ }
+
+ public int getTag()
+ {
+ return tag;
+ }
+
+ public byte[] getContents()
+ {
+ return Arrays.clone(contents);
+ }
+
+ public void encode(
+ BCPGOutputStream out)
+ throws IOException
+ {
+ out.writePacket(tag, contents, true);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java b/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java
index 6be9632a..d362bb93 100644
--- a/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java
+++ b/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java
@@ -1,185 +1,185 @@
-package org.bouncycastle.bcpg;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * basic packet for a PGP secret key
- */
-public class SecretKeyPacket
- extends ContainedPacket implements PublicKeyAlgorithmTags
-{
- public static final int USAGE_NONE = 0x00;
- public static final int USAGE_CHECKSUM = 0xff;
- public static final int USAGE_SHA1 = 0xfe;
-
- private PublicKeyPacket pubKeyPacket;
- private byte[] secKeyData;
- private int s2kUsage;
- private int encAlgorithm;
- private S2K s2k;
- private byte[] iv;
-
- /**
- *
- * @param in
- * @throws IOException
- */
- SecretKeyPacket(
- BCPGInputStream in)
- throws IOException
- {
- if (this instanceof SecretSubkeyPacket)
- {
- pubKeyPacket = new PublicSubkeyPacket(in);
- }
- else
- {
- pubKeyPacket = new PublicKeyPacket(in);
- }
-
- s2kUsage = in.read();
-
- if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
- {
- encAlgorithm = in.read();
- s2k = new S2K(in);
- }
- else
- {
- encAlgorithm = s2kUsage;
- }
-
- if (!(s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K && s2k.getProtectionMode() == 0x01))
- {
- if (s2kUsage != 0)
- {
- if (encAlgorithm < 7)
- {
- iv = new byte[8];
- }
- else
- {
- iv = new byte[16];
- }
- in.readFully(iv, 0, iv.length);
- }
- }
-
- this.secKeyData = in.readAll();
- }
-
- /**
- *
- * @param pubKeyPacket
- * @param encAlgorithm
- * @param s2k
- * @param iv
- * @param secKeyData
- */
- public SecretKeyPacket(
- PublicKeyPacket pubKeyPacket,
- int encAlgorithm,
- S2K s2k,
- byte[] iv,
- byte[] secKeyData)
- {
- this.pubKeyPacket = pubKeyPacket;
- this.encAlgorithm = encAlgorithm;
-
- if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL)
- {
- this.s2kUsage = USAGE_CHECKSUM;
- }
- else
- {
- this.s2kUsage = USAGE_NONE;
- }
-
- this.s2k = s2k;
- this.iv = iv;
- this.secKeyData = secKeyData;
- }
-
- public SecretKeyPacket(
- PublicKeyPacket pubKeyPacket,
- int encAlgorithm,
- int s2kUsage,
- S2K s2k,
- byte[] iv,
- byte[] secKeyData)
- {
- this.pubKeyPacket = pubKeyPacket;
- this.encAlgorithm = encAlgorithm;
- this.s2kUsage = s2kUsage;
- this.s2k = s2k;
- this.iv = iv;
- this.secKeyData = secKeyData;
- }
-
- public int getEncAlgorithm()
- {
- return encAlgorithm;
- }
-
- public int getS2KUsage()
- {
- return s2kUsage;
- }
-
- public byte[] getIV()
- {
- return iv;
- }
-
- public S2K getS2K()
- {
- return s2k;
- }
-
- public PublicKeyPacket getPublicKeyPacket()
- {
- return pubKeyPacket;
- }
-
- public byte[] getSecretKeyData()
- {
- return secKeyData;
- }
-
- public byte[] getEncodedContents()
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- BCPGOutputStream pOut = new BCPGOutputStream(bOut);
-
- pOut.write(pubKeyPacket.getEncodedContents());
-
- pOut.write(s2kUsage);
-
- if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
- {
- pOut.write(encAlgorithm);
- pOut.writeObject(s2k);
- }
-
- if (iv != null)
- {
- pOut.write(iv);
- }
-
- if (secKeyData != null && secKeyData.length > 0)
- {
- pOut.write(secKeyData);
- }
-
- return bOut.toByteArray();
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(SECRET_KEY, getEncodedContents(), true);
- }
-}
+package org.bouncycastle.bcpg;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * basic packet for a PGP secret key
+ */
+public class SecretKeyPacket
+ extends ContainedPacket implements PublicKeyAlgorithmTags
+{
+ public static final int USAGE_NONE = 0x00;
+ public static final int USAGE_CHECKSUM = 0xff;
+ public static final int USAGE_SHA1 = 0xfe;
+
+ private PublicKeyPacket pubKeyPacket;
+ private byte[] secKeyData;
+ private int s2kUsage;
+ private int encAlgorithm;
+ private S2K s2k;
+ private byte[] iv;
+
+ /**
+ *
+ * @param in
+ * @throws IOException
+ */
+ SecretKeyPacket(
+ BCPGInputStream in)
+ throws IOException
+ {
+ if (this instanceof SecretSubkeyPacket)
+ {
+ pubKeyPacket = new PublicSubkeyPacket(in);
+ }
+ else
+ {
+ pubKeyPacket = new PublicKeyPacket(in);
+ }
+
+ s2kUsage = in.read();
+
+ if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
+ {
+ encAlgorithm = in.read();
+ s2k = new S2K(in);
+ }
+ else
+ {
+ encAlgorithm = s2kUsage;
+ }
+
+ if (!(s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K && s2k.getProtectionMode() == 0x01))
+ {
+ if (s2kUsage != 0)
+ {
+ if (encAlgorithm < 7)
+ {
+ iv = new byte[8];
+ }
+ else
+ {
+ iv = new byte[16];
+ }
+ in.readFully(iv, 0, iv.length);
+ }
+ }
+
+ this.secKeyData = in.readAll();
+ }
+
+ /**
+ *
+ * @param pubKeyPacket
+ * @param encAlgorithm
+ * @param s2k
+ * @param iv
+ * @param secKeyData
+ */
+ public SecretKeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ int encAlgorithm,
+ S2K s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ {
+ this.pubKeyPacket = pubKeyPacket;
+ this.encAlgorithm = encAlgorithm;
+
+ if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL)
+ {
+ this.s2kUsage = USAGE_CHECKSUM;
+ }
+ else
+ {
+ this.s2kUsage = USAGE_NONE;
+ }
+
+ this.s2k = s2k;
+ this.iv = iv;
+ this.secKeyData = secKeyData;
+ }
+
+ public SecretKeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ int encAlgorithm,
+ int s2kUsage,
+ S2K s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ {
+ this.pubKeyPacket = pubKeyPacket;
+ this.encAlgorithm = encAlgorithm;
+ this.s2kUsage = s2kUsage;
+ this.s2k = s2k;
+ this.iv = iv;
+ this.secKeyData = secKeyData;
+ }
+
+ public int getEncAlgorithm()
+ {
+ return encAlgorithm;
+ }
+
+ public int getS2KUsage()
+ {
+ return s2kUsage;
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+
+ public S2K getS2K()
+ {
+ return s2k;
+ }
+
+ public PublicKeyPacket getPublicKeyPacket()
+ {
+ return pubKeyPacket;
+ }
+
+ public byte[] getSecretKeyData()
+ {
+ return secKeyData;
+ }
+
+ public byte[] getEncodedContents()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ BCPGOutputStream pOut = new BCPGOutputStream(bOut);
+
+ pOut.write(pubKeyPacket.getEncodedContents());
+
+ pOut.write(s2kUsage);
+
+ if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
+ {
+ pOut.write(encAlgorithm);
+ pOut.writeObject(s2k);
+ }
+
+ if (iv != null)
+ {
+ pOut.write(iv);
+ }
+
+ if (secKeyData != null && secKeyData.length > 0)
+ {
+ pOut.write(secKeyData);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ public void encode(
+ BCPGOutputStream out)
+ throws IOException
+ {
+ out.writePacket(SECRET_KEY, getEncodedContents(), true);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java b/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java
index 3e4218fe..37769fef 100644
--- a/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java
+++ b/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java
@@ -1,90 +1,90 @@
-package org.bouncycastle.bcpg;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * Basic type for a symmetric encrypted session key packet
- */
-public class SymmetricKeyEncSessionPacket
- extends ContainedPacket
-{
- private int version;
- private int encAlgorithm;
- private S2K s2k;
- private byte[] secKeyData;
-
- public SymmetricKeyEncSessionPacket(
- BCPGInputStream in)
- throws IOException
- {
- version = in.read();
- encAlgorithm = in.read();
-
- s2k = new S2K(in);
-
- this.secKeyData = in.readAll();
- }
-
- public SymmetricKeyEncSessionPacket(
- int encAlgorithm,
- S2K s2k,
- byte[] secKeyData)
- {
- this.version = 4;
- this.encAlgorithm = encAlgorithm;
- this.s2k = s2k;
- this.secKeyData = secKeyData;
- }
-
- /**
- * @return int
- */
- public int getEncAlgorithm()
- {
- return encAlgorithm;
- }
-
- /**
- * @return S2K
- */
- public S2K getS2K()
- {
- return s2k;
- }
-
- /**
- * @return byte[]
- */
- public byte[] getSecKeyData()
- {
- return secKeyData;
- }
-
- /**
- * @return int
- */
- public int getVersion()
- {
- return version;
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- BCPGOutputStream pOut = new BCPGOutputStream(bOut);
-
- pOut.write(version);
- pOut.write(encAlgorithm);
- pOut.writeObject(s2k);
-
- if (secKeyData != null && secKeyData.length > 0)
- {
- pOut.write(secKeyData);
- }
-
- out.writePacket(SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray(), true);
- }
-}
+package org.bouncycastle.bcpg;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Basic type for a symmetric encrypted session key packet
+ */
+public class SymmetricKeyEncSessionPacket
+ extends ContainedPacket
+{
+ private int version;
+ private int encAlgorithm;
+ private S2K s2k;
+ private byte[] secKeyData;
+
+ public SymmetricKeyEncSessionPacket(
+ BCPGInputStream in)
+ throws IOException
+ {
+ version = in.read();
+ encAlgorithm = in.read();
+
+ s2k = new S2K(in);
+
+ this.secKeyData = in.readAll();
+ }
+
+ public SymmetricKeyEncSessionPacket(
+ int encAlgorithm,
+ S2K s2k,
+ byte[] secKeyData)
+ {
+ this.version = 4;
+ this.encAlgorithm = encAlgorithm;
+ this.s2k = s2k;
+ this.secKeyData = secKeyData;
+ }
+
+ /**
+ * @return int
+ */
+ public int getEncAlgorithm()
+ {
+ return encAlgorithm;
+ }
+
+ /**
+ * @return S2K
+ */
+ public S2K getS2K()
+ {
+ return s2k;
+ }
+
+ /**
+ * @return byte[]
+ */
+ public byte[] getSecKeyData()
+ {
+ return secKeyData;
+ }
+
+ /**
+ * @return int
+ */
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public void encode(
+ BCPGOutputStream out)
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ BCPGOutputStream pOut = new BCPGOutputStream(bOut);
+
+ pOut.write(version);
+ pOut.write(encAlgorithm);
+ pOut.writeObject(s2k);
+
+ if (secKeyData != null && secKeyData.length > 0)
+ {
+ pOut.write(secKeyData);
+ }
+
+ out.writePacket(SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray(), true);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java b/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java
index dff7e5ab..15ae71b1 100644
--- a/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java
+++ b/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java
@@ -1,39 +1,39 @@
-package org.bouncycastle.bcpg;
-
-import java.io.IOException;
-
-import org.bouncycastle.util.Strings;
-
-/**
- * Basic type for a user ID packet.
- */
-public class UserIDPacket
- extends ContainedPacket
-{
- private byte[] idData;
-
- public UserIDPacket(
- BCPGInputStream in)
- throws IOException
- {
- this.idData = in.readAll();
- }
-
- public UserIDPacket(
- String id)
- {
- this.idData = Strings.toUTF8ByteArray(id);
- }
-
- public String getID()
- {
- return Strings.fromUTF8ByteArray(idData);
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(USER_ID, idData, true);
- }
-}
+package org.bouncycastle.bcpg;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Strings;
+
+/**
+ * Basic type for a user ID packet.
+ */
+public class UserIDPacket
+ extends ContainedPacket
+{
+ private byte[] idData;
+
+ public UserIDPacket(
+ BCPGInputStream in)
+ throws IOException
+ {
+ this.idData = in.readAll();
+ }
+
+ public UserIDPacket(
+ String id)
+ {
+ this.idData = Strings.toUTF8ByteArray(id);
+ }
+
+ public String getID()
+ {
+ return Strings.fromUTF8ByteArray(idData);
+ }
+
+ public void encode(
+ BCPGOutputStream out)
+ throws IOException
+ {
+ out.writePacket(USER_ID, idData, true);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/cert/CertRuntimeException.java b/src/main/java/org/bouncycastle/cert/CertRuntimeException.java
new file mode 100644
index 00000000..5384148a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/cert/CertRuntimeException.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.cert;
+
+public class CertRuntimeException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public CertRuntimeException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java b/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java
index 43c5948d..9afaf040 100644
--- a/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java
+++ b/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java
@@ -118,7 +118,7 @@ public class X509ExtensionUtils
}
catch (IOException e)
{ // it's hard to imagine this happening, but yes it does!
- throw new IllegalStateException("unable to calculate identifier: " + e.getMessage(), e);
+ throw new CertRuntimeException("unable to calculate identifier: " + e.getMessage(), e);
}
return calculator.getDigest();
diff --git a/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java b/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java
index 8a376952..2706c401 100644
--- a/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java
+++ b/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java
@@ -81,6 +81,10 @@ public class OCSPReq
try
{
this.req = OCSPRequest.getInstance(aIn.readObject());
+ if (req == null)
+ {
+ throw new CertIOException("malformed request: no request data found");
+ }
this.extensions = req.getTbsRequest().getRequestExtensions();
}
catch (IllegalArgumentException e)
diff --git a/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java b/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java
index 43c240fc..e7e07705 100644
--- a/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java
+++ b/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java
@@ -65,6 +65,11 @@ public class OCSPResp
{
throw new CertIOException("malformed response: " + e.getMessage(), e);
}
+
+ if (resp == null)
+ {
+ throw new CertIOException("malformed response: no response data found");
+ }
}
public int getStatus()
diff --git a/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java b/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java
index 7b8f57a8..af1ffe06 100644
--- a/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java
+++ b/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java
@@ -1,121 +1,115 @@
-package org.bouncycastle.cms;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class RecipientInformationStore
-{
- private final List all; //ArrayList[RecipientInformation]
- private final Map table = new HashMap(); // HashMap[RecipientID, ArrayList[RecipientInformation]]
-
- public RecipientInformationStore(
- Collection recipientInfos)
- {
- Iterator it = recipientInfos.iterator();
-
- while (it.hasNext())
- {
- RecipientInformation recipientInformation = (RecipientInformation)it.next();
- RecipientId rid = recipientInformation.getRID();
-
- List list = (ArrayList)table.get(rid);
- if (list == null)
- {
- list = new ArrayList(1);
- table.put(rid, list);
- }
-
- list.add(recipientInformation);
- }
-
- this.all = new ArrayList(recipientInfos);
- }
-
- /**
- * Return the first RecipientInformation object that matches the
- * passed in selector. Null if there are no matches.
- *
- * @param selector to identify a recipient
- * @return a single RecipientInformation object. Null if none matches.
- */
- public RecipientInformation get(
- RecipientId selector)
- {
- Collection list = getRecipients(selector);
-
- return list.size() == 0 ? null : (RecipientInformation)list.iterator().next();
- }
-
- /**
- * Return the number of recipients in the collection.
- *
- * @return number of recipients identified.
- */
- public int size()
- {
- return all.size();
- }
-
- /**
- * Return all recipients in the collection
- *
- * @return a collection of recipients.
- */
- public Collection getRecipients()
- {
- return new ArrayList(all);
- }
-
- /**
- * Return possible empty collection with recipients matching the passed in RecipientId
- *
- * @param selector a recipient id to select against.
- * @return a collection of RecipientInformation objects.
- */
- public Collection getRecipients(
- RecipientId selector)
- {
- if (selector instanceof KeyTransRecipientId)
- {
- KeyTransRecipientId keyTrans = (KeyTransRecipientId)selector;
- byte[] subjectKeyId = keyTrans.getSubjectKeyIdentifier();
-
- if (keyTrans.getIssuer() != null && subjectKeyId != null)
- {
- List results = new ArrayList();
-
- Collection match1 = getRecipients(new KeyTransRecipientId(keyTrans.getIssuer(), keyTrans.getSerialNumber()));
-
- if (match1 != null)
- {
- results.addAll(match1);
- }
-
- Collection match2 = getRecipients(new KeyTransRecipientId(subjectKeyId));
-
- if (match2 != null)
- {
- results.addAll(match2);
- }
-
- return results;
- }
- else
- {
- List list = (ArrayList)table.get(selector);
-
- return list == null ? new ArrayList() : new ArrayList(list);
- }
- }
- else
- {
- List list = (ArrayList)table.get(selector);
-
- return list == null ? new ArrayList() : new ArrayList(list);
- }
- }
-}
+package org.bouncycastle.cms;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.bouncycastle.asn1.x500.X500Name;
+
+public class RecipientInformationStore
+{
+ private final List all; //ArrayList[RecipientInformation]
+ private final Map table = new HashMap(); // HashMap[RecipientID, ArrayList[RecipientInformation]]
+
+ public RecipientInformationStore(
+ Collection recipientInfos)
+ {
+ Iterator it = recipientInfos.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipientInformation = (RecipientInformation)it.next();
+ RecipientId rid = recipientInformation.getRID();
+
+ List list = (ArrayList)table.get(rid);
+ if (list == null)
+ {
+ list = new ArrayList(1);
+ table.put(rid, list);
+ }
+
+ list.add(recipientInformation);
+ }
+
+ this.all = new ArrayList(recipientInfos);
+ }
+
+ /**
+ * Return the first RecipientInformation object that matches the
+ * passed in selector. Null if there are no matches.
+ *
+ * @param selector to identify a recipient
+ * @return a single RecipientInformation object. Null if none matches.
+ */
+ public RecipientInformation get(
+ RecipientId selector)
+ {
+ Collection list = getRecipients(selector);
+
+ return list.size() == 0 ? null : (RecipientInformation)list.iterator().next();
+ }
+
+ /**
+ * Return the number of recipients in the collection.
+ *
+ * @return number of recipients identified.
+ */
+ public int size()
+ {
+ return all.size();
+ }
+
+ /**
+ * Return all recipients in the collection
+ *
+ * @return a collection of recipients.
+ */
+ public Collection getRecipients()
+ {
+ return new ArrayList(all);
+ }
+
+ /**
+ * Return possible empty collection with recipients matching the passed in RecipientId
+ *
+ * @param selector a recipient id to select against.
+ * @return a collection of RecipientInformation objects.
+ */
+ public Collection getRecipients(
+ RecipientId selector)
+ {
+ if (selector instanceof KeyTransRecipientId)
+ {
+ KeyTransRecipientId keyTrans = (KeyTransRecipientId)selector;
+
+ X500Name issuer = keyTrans.getIssuer();
+ byte[] subjectKeyId = keyTrans.getSubjectKeyIdentifier();
+
+ if (issuer != null && subjectKeyId != null)
+ {
+ List results = new ArrayList();
+
+ Collection match1 = getRecipients(new KeyTransRecipientId(issuer, keyTrans.getSerialNumber()));
+ if (match1 != null)
+ {
+ results.addAll(match1);
+ }
+
+ Collection match2 = getRecipients(new KeyTransRecipientId(subjectKeyId));
+ if (match2 != null)
+ {
+ results.addAll(match2);
+ }
+
+ return results;
+ }
+ }
+
+ List list = (ArrayList)table.get(selector);
+
+ return list == null ? new ArrayList() : new ArrayList(list);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/KeyEncapsulation.java b/src/main/java/org/bouncycastle/crypto/KeyEncapsulation.java
new file mode 100755
index 00000000..16744573
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/KeyEncapsulation.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto;
+
+/**
+ * The basic interface for key encapsulation mechanisms.
+ */
+public interface KeyEncapsulation
+{
+ /**
+ * Initialise the key encapsulation mechanism.
+ */
+ public void init(CipherParameters param);
+
+ /**
+ * Encapsulate a randomly generated session key.
+ */
+ public CipherParameters encrypt(byte[] out, int outOff, int keyLen);
+
+ /**
+ * Decapsulate an encapsulated session key.
+ */
+ public CipherParameters decrypt(byte[] in, int inOff, int inLen, int keyLen);
+}
diff --git a/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java b/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
index 356f8b6e..947bc5c4 100644
--- a/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
@@ -1,131 +1,131 @@
-package org.bouncycastle.crypto.agreement.kdf;
-
-import java.io.IOException;
-
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * RFC 2631 Diffie-hellman KEK derivation function.
- */
-public class DHKEKGenerator
- implements DerivationFunction
-{
- private final Digest digest;
-
- private DERObjectIdentifier algorithm;
- private int keySize;
- private byte[] z;
- private byte[] partyAInfo;
-
- public DHKEKGenerator(
- Digest digest)
- {
- this.digest = digest;
- }
-
- public void init(DerivationParameters param)
- {
- DHKDFParameters params = (DHKDFParameters)param;
-
- this.algorithm = params.getAlgorithm();
- this.keySize = params.getKeySize();
- this.z = params.getZ();
- this.partyAInfo = params.getExtraInfo();
- }
-
- public Digest getDigest()
- {
- return digest;
- }
-
- public int generateBytes(byte[] out, int outOff, int len)
- throws DataLengthException, IllegalArgumentException
- {
- if ((out.length - len) < outOff)
- {
- throw new DataLengthException("output buffer too small");
- }
-
- long oBytes = len;
- int outLen = digest.getDigestSize();
-
- //
- // this is at odds with the standard implementation, the
- // maximum value should be hBits * (2^32 - 1) where hBits
- // is the digest output size in bits. We can't have an
- // array with a long index at the moment...
- //
- if (oBytes > ((2L << 32) - 1))
- {
- throw new IllegalArgumentException("Output length too large");
- }
-
- int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
- byte[] dig = new byte[digest.getDigestSize()];
-
- int counter = 1;
-
- for (int i = 0; i < cThreshold; i++)
- {
- digest.update(z, 0, z.length);
-
- // OtherInfo
- ASN1EncodableVector v1 = new ASN1EncodableVector();
- // KeySpecificInfo
- ASN1EncodableVector v2 = new ASN1EncodableVector();
-
- v2.add(algorithm);
- v2.add(new DEROctetString(Pack.intToBigEndian(counter)));
-
- v1.add(new DERSequence(v2));
-
- if (partyAInfo != null)
- {
- v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo)));
- }
-
- v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
-
- try
- {
- byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER);
-
- digest.update(other, 0, other.length);
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage());
- }
-
- digest.doFinal(dig, 0);
-
- if (len > outLen)
- {
- System.arraycopy(dig, 0, out, outOff, outLen);
- outOff += outLen;
- len -= outLen;
- }
- else
- {
- System.arraycopy(dig, 0, out, outOff, len);
- }
-
- counter++;
- }
-
- digest.reset();
-
- return (int)oBytes;
- }
-}
+package org.bouncycastle.crypto.agreement.kdf;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.util.Pack;
+
+/**
+ * RFC 2631 Diffie-hellman KEK derivation function.
+ */
+public class DHKEKGenerator
+ implements DerivationFunction
+{
+ private final Digest digest;
+
+ private DERObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+ private byte[] partyAInfo;
+
+ public DHKEKGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ }
+
+ public void init(DerivationParameters param)
+ {
+ DHKDFParameters params = (DHKDFParameters)param;
+
+ this.algorithm = params.getAlgorithm();
+ this.keySize = params.getKeySize();
+ this.z = params.getZ();
+ this.partyAInfo = params.getExtraInfo();
+ }
+
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ public int generateBytes(byte[] out, int outOff, int len)
+ throws DataLengthException, IllegalArgumentException
+ {
+ if ((out.length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = len;
+ int outLen = digest.getDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new IllegalArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.getDigestSize()];
+
+ int counter = 1;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.update(z, 0, z.length);
+
+ // OtherInfo
+ ASN1EncodableVector v1 = new ASN1EncodableVector();
+ // KeySpecificInfo
+ ASN1EncodableVector v2 = new ASN1EncodableVector();
+
+ v2.add(algorithm);
+ v2.add(new DEROctetString(Pack.intToBigEndian(counter)));
+
+ v1.add(new DERSequence(v2));
+
+ if (partyAInfo != null)
+ {
+ v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo)));
+ }
+
+ v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
+
+ try
+ {
+ byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER);
+
+ digest.update(other, 0, other.length);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage());
+ }
+
+ digest.doFinal(dig, 0);
+
+ if (len > outLen)
+ {
+ System.arraycopy(dig, 0, out, outOff, outLen);
+ outOff += outLen;
+ len -= outLen;
+ }
+ else
+ {
+ System.arraycopy(dig, 0, out, outOff, len);
+ }
+
+ counter++;
+ }
+
+ digest.reset();
+
+ return (int)oBytes;
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java b/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java
index 03ca321f..68039533 100644
--- a/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java
@@ -1,74 +1,74 @@
-package org.bouncycastle.crypto.agreement.kdf;
-
-import java.io.IOException;
-
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * X9.63 based key derivation function for ECDH CMS.
- */
-public class ECDHKEKGenerator
- implements DerivationFunction
-{
- private DerivationFunction kdf;
-
- private ASN1ObjectIdentifier algorithm;
- private int keySize;
- private byte[] z;
-
- public ECDHKEKGenerator(
- Digest digest)
- {
- this.kdf = new KDF2BytesGenerator(digest);
- }
-
- public void init(DerivationParameters param)
- {
- DHKDFParameters params = (DHKDFParameters)param;
-
- this.algorithm = params.getAlgorithm();
- this.keySize = params.getKeySize();
- this.z = params.getZ();
- }
-
- public Digest getDigest()
- {
- return kdf.getDigest();
- }
-
- public int generateBytes(byte[] out, int outOff, int len)
- throws DataLengthException, IllegalArgumentException
- {
- // TODO Create an ASN.1 class for this (RFC3278)
- // ECC-CMS-SharedInfo
- ASN1EncodableVector v = new ASN1EncodableVector();
-
- v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE));
- v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
-
- try
- {
- kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER)));
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("unable to initialise kdf: " + e.getMessage());
- }
-
- return kdf.generateBytes(out, outOff, len);
- }
-}
+package org.bouncycastle.crypto.agreement.kdf;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.util.Pack;
+
+/**
+ * X9.63 based key derivation function for ECDH CMS.
+ */
+public class ECDHKEKGenerator
+ implements DerivationFunction
+{
+ private DerivationFunction kdf;
+
+ private ASN1ObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+
+ public ECDHKEKGenerator(
+ Digest digest)
+ {
+ this.kdf = new KDF2BytesGenerator(digest);
+ }
+
+ public void init(DerivationParameters param)
+ {
+ DHKDFParameters params = (DHKDFParameters)param;
+
+ this.algorithm = params.getAlgorithm();
+ this.keySize = params.getKeySize();
+ this.z = params.getZ();
+ }
+
+ public Digest getDigest()
+ {
+ return kdf.getDigest();
+ }
+
+ public int generateBytes(byte[] out, int outOff, int len)
+ throws DataLengthException, IllegalArgumentException
+ {
+ // TODO Create an ASN.1 class for this (RFC3278)
+ // ECC-CMS-SharedInfo
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE));
+ v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
+
+ try
+ {
+ kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to initialise kdf: " + e.getMessage());
+ }
+
+ return kdf.generateBytes(out, outOff, len);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/GOST3411Digest.java b/src/main/java/org/bouncycastle/crypto/digests/GOST3411Digest.java
index 956fada0..38a52aab 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/GOST3411Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/GOST3411Digest.java
@@ -7,12 +7,13 @@ import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithSBox;
import org.bouncycastle.crypto.util.Pack;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Memoable;
/**
* implementation of GOST R 34.11-94
*/
public class GOST3411Digest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int DIGEST_LENGTH = 32;
@@ -56,22 +57,7 @@ public class GOST3411Digest
*/
public GOST3411Digest(GOST3411Digest t)
{
- this.sBox = t.sBox;
- cipher.init(true, new ParametersWithSBox(null, sBox));
-
- reset();
-
- System.arraycopy(t.H, 0, this.H, 0, t.H.length);
- System.arraycopy(t.L, 0, this.L, 0, t.L.length);
- System.arraycopy(t.M, 0, this.M, 0, t.M.length);
- System.arraycopy(t.Sum, 0, this.Sum, 0, t.Sum.length);
- System.arraycopy(t.C[1], 0, this.C[1], 0, t.C[1].length);
- System.arraycopy(t.C[2], 0, this.C[2], 0, t.C[2].length);
- System.arraycopy(t.C[3], 0, this.C[3], 0, t.C[3].length);
- System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
-
- this.xBufOff = t.xBufOff;
- this.byteCount = t.byteCount;
+ reset(t);
}
public String getAlgorithmName()
@@ -344,6 +330,33 @@ public class GOST3411Digest
{
return 32;
}
+
+ public Memoable copy()
+ {
+ return new GOST3411Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ GOST3411Digest t = (GOST3411Digest)other;
+
+ this.sBox = t.sBox;
+ cipher.init(true, new ParametersWithSBox(null, sBox));
+
+ reset();
+
+ System.arraycopy(t.H, 0, this.H, 0, t.H.length);
+ System.arraycopy(t.L, 0, this.L, 0, t.L.length);
+ System.arraycopy(t.M, 0, this.M, 0, t.M.length);
+ System.arraycopy(t.Sum, 0, this.Sum, 0, t.Sum.length);
+ System.arraycopy(t.C[1], 0, this.C[1], 0, t.C[1].length);
+ System.arraycopy(t.C[2], 0, this.C[2], 0, t.C[2].length);
+ System.arraycopy(t.C[3], 0, this.C[3], 0, t.C[3].length);
+ System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
+
+ this.xBufOff = t.xBufOff;
+ this.byteCount = t.byteCount;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
index f2c99674..15f3ebbd 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -1,13 +1,14 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.util.Memoable;
/**
* base implementation of MD4 family style digest as outlined in
* "Handbook of Applied Cryptography", pages 344 - 347.
*/
public abstract class GeneralDigest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 64;
private byte[] xBuf;
@@ -32,6 +33,12 @@ public abstract class GeneralDigest
protected GeneralDigest(GeneralDigest t)
{
xBuf = new byte[t.xBuf.length];
+
+ copyIn(t);
+ }
+
+ protected void copyIn(GeneralDigest t)
+ {
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
xBufOff = t.xBufOff;
diff --git a/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java b/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
index 22d457bf..5c79e4ee 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
@@ -2,12 +2,13 @@ package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
* Base class for SHA-384 and SHA-512.
*/
public abstract class LongDigest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 128;
@@ -41,6 +42,12 @@ public abstract class LongDigest
protected LongDigest(LongDigest t)
{
xBuf = new byte[t.xBuf.length];
+
+ copyIn(t);
+ }
+
+ protected void copyIn(LongDigest t)
+ {
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
xBufOff = t.xBufOff;
diff --git a/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java b/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java
index bd942a1c..f96b4a15 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java
@@ -1,12 +1,14 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.*;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of MD2
* as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
*/
public class MD2Digest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int DIGEST_LENGTH = 16;
@@ -24,8 +26,14 @@ public class MD2Digest
{
reset();
}
+
public MD2Digest(MD2Digest t)
{
+ copyIn(t);
+ }
+
+ private void copyIn(MD2Digest t)
+ {
System.arraycopy(t.X, 0, X, 0, t.X.length);
xOff = t.xOff;
System.arraycopy(t.M, 0, M, 0, t.M.length);
@@ -33,6 +41,7 @@ public class MD2Digest
System.arraycopy(t.C, 0, C, 0, t.C.length);
COff = t.COff;
}
+
/**
* return the algorithm name
*
@@ -232,6 +241,18 @@ public class MD2Digest
{
return 16;
}
+
+ public Memoable copy()
+ {
+ return new MD2Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ MD2Digest d = (MD2Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java b/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java
index 2a8084f9..68532bd2 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
* Computer Science and RSA Data Security, Inc.
@@ -34,6 +36,13 @@ public class MD4Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(MD4Digest t)
+ {
+ super.copyIn(t);
+
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
@@ -267,4 +276,16 @@ public class MD4Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new MD4Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ MD4Digest d = (MD4Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java b/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
index 05ed27a6..ff9cedf0 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
*/
@@ -30,6 +32,13 @@ public class MD5Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(MD5Digest t)
+ {
+ super.copyIn(t);
+
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
@@ -299,4 +308,16 @@ public class MD5Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new MD5Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ MD5Digest d = (MD5Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/NonMemoableDigest.java b/src/main/java/org/bouncycastle/crypto/digests/NonMemoableDigest.java
new file mode 100644
index 00000000..87a4d249
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/digests/NonMemoableDigest.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * Wrapper removes exposure to the Memoable interface on an ExtendedDigest implementation.
+ */
+public class NonMemoableDigest
+ implements ExtendedDigest
+{
+ private ExtendedDigest baseDigest;
+
+ /**
+ * Base constructor.
+ *
+ * @param baseDigest underlying digest to use.
+ * @exception IllegalArgumentException if baseDigest is null
+ */
+ public NonMemoableDigest(
+ ExtendedDigest baseDigest)
+ {
+ if (baseDigest == null)
+ {
+ throw new IllegalArgumentException("baseDigest must not be null");
+ }
+
+ this.baseDigest = baseDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return baseDigest.getAlgorithmName();
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ baseDigest.update(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ baseDigest.update(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ return baseDigest.doFinal(out, outOff);
+ }
+
+ public void reset()
+ {
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return baseDigest.getByteLength();
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD128Digest.java b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD128Digest.java
index 46fd8b39..ec7fa859 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD128Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD128Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of RIPEMD128
*/
@@ -30,6 +32,13 @@ public class RIPEMD128Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(RIPEMD128Digest t)
+ {
+ super.copyIn(t);
+
H0 = t.H0;
H1 = t.H1;
H2 = t.H2;
@@ -458,4 +467,16 @@ public class RIPEMD128Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new RIPEMD128Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ RIPEMD128Digest d = (RIPEMD128Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD160Digest.java b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD160Digest.java
index 2351357c..20c81e68 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD160Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD160Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of RIPEMD see,
* http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
@@ -31,6 +33,13 @@ public class RIPEMD160Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(RIPEMD160Digest t)
+ {
+ super.copyIn(t);
+
H0 = t.H0;
H1 = t.H1;
H2 = t.H2;
@@ -419,4 +428,16 @@ public class RIPEMD160Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new RIPEMD160Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ RIPEMD160Digest d = (RIPEMD160Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD256Digest.java b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD256Digest.java
index 3d92e4a3..86746b45 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD256Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD256Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of RIPEMD256.
* <p>
@@ -32,6 +34,13 @@ public class RIPEMD256Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(RIPEMD256Digest t)
+ {
+ super.copyIn(t);
+
H0 = t.H0;
H1 = t.H1;
H2 = t.H2;
@@ -473,4 +482,16 @@ public class RIPEMD256Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new RIPEMD256Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ RIPEMD256Digest d = (RIPEMD256Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD320Digest.java b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD320Digest.java
index e2cda588..32775e77 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/RIPEMD320Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/RIPEMD320Digest.java
@@ -1,6 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+
/**
* implementation of RIPEMD 320.
* <p>
@@ -33,6 +35,12 @@ public class RIPEMD320Digest
{
super(t);
+ doCopy(t);
+ }
+
+ private void doCopy(RIPEMD320Digest t)
+ {
+ super.copyIn(t);
H0 = t.H0;
H1 = t.H1;
H2 = t.H2;
@@ -458,4 +466,16 @@ public class RIPEMD320Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new RIPEMD320Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ RIPEMD320Digest d = (RIPEMD320Digest)other;
+
+ doCopy(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
index 1b47fd3c..21b1024e 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
* implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
@@ -34,6 +35,11 @@ public class SHA1Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(SHA1Digest t)
+ {
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
@@ -283,6 +289,19 @@ public class SHA1Digest
X[i] = 0;
}
}
+
+ public Memoable copy()
+ {
+ return new SHA1Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA1Digest d = (SHA1Digest)other;
+
+ super.copyIn(d);
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
index d144c54b..d430321b 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -1,8 +1,8 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.digests.GeneralDigest;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
@@ -42,6 +42,13 @@ public class SHA224Digest
{
super(t);
+ doCopy(t);
+ }
+
+ private void doCopy(SHA224Digest t)
+ {
+ super.copyIn(t);
+
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
@@ -288,5 +295,17 @@ public class SHA224Digest
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
+
+ public Memoable copy()
+ {
+ return new SHA224Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA224Digest d = (SHA224Digest)other;
+
+ doCopy(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
index abd9c1bb..a2ceda3d 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -1,8 +1,8 @@
package org.bouncycastle.crypto.digests;
-import org.bouncycastle.crypto.digests.GeneralDigest;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
@@ -42,6 +42,13 @@ public class SHA256Digest
{
super(t);
+ copyIn(t);
+ }
+
+ private void copyIn(SHA256Digest t)
+ {
+ super.copyIn(t);
+
H1 = t.H1;
H2 = t.H2;
H3 = t.H3;
@@ -291,5 +298,17 @@ public class SHA256Digest
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
+
+ public Memoable copy()
+ {
+ return new SHA256Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA256Digest d = (SHA256Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
index cdd979a9..75d195d4 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
@@ -17,7 +18,6 @@ import org.bouncycastle.crypto.util.Pack;
public class SHA384Digest
extends LongDigest
{
-
private static final int DIGEST_LENGTH = 48;
/**
@@ -84,4 +84,16 @@ public class SHA384Digest
H7 = 0xdb0c2e0d64f98fa7l;
H8 = 0x47b5481dbefa4fa4l;
}
+
+ public Memoable copy()
+ {
+ return new SHA384Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA384Digest d = (SHA384Digest)other;
+
+ super.copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
index 34a8e4e4..7db63ad2 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
/**
@@ -85,5 +86,17 @@ public class SHA512Digest
H7 = 0x1f83d9abfb41bd6bL;
H8 = 0x5be0cd19137e2179L;
}
+
+ public Memoable copy()
+ {
+ return new SHA512Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA512Digest d = (SHA512Digest)other;
+
+ copyIn(d);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java b/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java
index 459ade16..46154618 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/SHA512tDigest.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.MemoableResetException;
+
/**
* FIPS 180-4 implementation of SHA-512/t
*/
@@ -47,14 +50,7 @@ public class SHA512tDigest
this.digestLength = t.digestLength;
- this.H1t = t.H1t;
- this.H2t = t.H2t;
- this.H3t = t.H3t;
- this.H4t = t.H4t;
- this.H5t = t.H5t;
- this.H6t = t.H6t;
- this.H7t = t.H7t;
- this.H8t = t.H8t;
+ reset(t);
}
public String getAlgorithmName()
@@ -180,4 +176,30 @@ public class SHA512tDigest
bs[off + num] = (byte)(n >>> shift);
}
}
+
+ public Memoable copy()
+ {
+ return new SHA512tDigest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SHA512tDigest t = (SHA512tDigest)other;
+
+ if (this.digestLength != t.digestLength)
+ {
+ throw new MemoableResetException("digestLength inappropriate in other");
+ }
+
+ super.copyIn(t);
+
+ this.H1t = t.H1t;
+ this.H2t = t.H2t;
+ this.H3t = t.H3t;
+ this.H4t = t.H4t;
+ this.H5t = t.H5t;
+ this.H6t = t.H6t;
+ this.H7t = t.H7t;
+ this.H8t = t.H8t;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/TigerDigest.java b/src/main/java/org/bouncycastle/crypto/digests/TigerDigest.java
index 0062ea92..2899e305 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/TigerDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/TigerDigest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.util.Memoable;
/**
* implementation of Tiger based on:
@@ -8,7 +9,7 @@ import org.bouncycastle.crypto.ExtendedDigest;
* http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
*/
public class TigerDigest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 64;
@@ -570,17 +571,7 @@ public class TigerDigest
*/
public TigerDigest(TigerDigest t)
{
- a = t.a;
- b = t.b;
- c = t.c;
-
- System.arraycopy(t.x, 0, x, 0, t.x.length);
- xOff = t.xOff;
-
- System.arraycopy(t.buf, 0, buf, 0, t.buf.length);
- bOff = t.bOff;
-
- byteCount = t.byteCount;
+ this.reset(t);
}
public String getAlgorithmName()
@@ -863,4 +854,26 @@ public class TigerDigest
{
return BYTE_LENGTH;
}
+
+ public Memoable copy()
+ {
+ return new TigerDigest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ TigerDigest t = (TigerDigest)other;
+
+ a = t.a;
+ b = t.b;
+ c = t.c;
+
+ System.arraycopy(t.x, 0, x, 0, t.x.length);
+ xOff = t.xOff;
+
+ System.arraycopy(t.buf, 0, buf, 0, t.buf.length);
+ bOff = t.bOff;
+
+ byteCount = t.byteCount;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/WhirlpoolDigest.java b/src/main/java/org/bouncycastle/crypto/digests/WhirlpoolDigest.java
index 6d350470..11e884cd 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/WhirlpoolDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/WhirlpoolDigest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Memoable;
/**
@@ -10,7 +11,7 @@ import org.bouncycastle.util.Arrays;
*
*/
public final class WhirlpoolDigest
- implements ExtendedDigest
+ implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 64;
@@ -136,19 +137,7 @@ public final class WhirlpoolDigest
*/
public WhirlpoolDigest(WhirlpoolDigest originalDigest)
{
- System.arraycopy(originalDigest._rc, 0, _rc, 0, _rc.length);
-
- System.arraycopy(originalDigest._buffer, 0, _buffer, 0, _buffer.length);
-
- this._bufferPos = originalDigest._bufferPos;
- System.arraycopy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.length);
-
- // -- internal hash state --
- System.arraycopy(originalDigest._hash, 0, _hash, 0, _hash.length);
- System.arraycopy(originalDigest._K, 0, _K, 0, _K.length);
- System.arraycopy(originalDigest._L, 0, _L, 0, _L.length);
- System.arraycopy(originalDigest._block, 0, _block, 0, _block.length);
- System.arraycopy(originalDigest._state, 0, _state, 0, _state.length);
+ reset(originalDigest);
}
public String getAlgorithmName()
@@ -393,4 +382,28 @@ public final class WhirlpoolDigest
{
return BYTE_LENGTH;
}
+
+ public Memoable copy()
+ {
+ return new WhirlpoolDigest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ WhirlpoolDigest originalDigest = (WhirlpoolDigest)other;
+
+ System.arraycopy(originalDigest._rc, 0, _rc, 0, _rc.length);
+
+ System.arraycopy(originalDigest._buffer, 0, _buffer, 0, _buffer.length);
+
+ this._bufferPos = originalDigest._bufferPos;
+ System.arraycopy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.length);
+
+ // -- internal hash state --
+ System.arraycopy(originalDigest._hash, 0, _hash, 0, _hash.length);
+ System.arraycopy(originalDigest._K, 0, _K, 0, _K.length);
+ System.arraycopy(originalDigest._L, 0, _L, 0, _L.length);
+ System.arraycopy(originalDigest._block, 0, _block, 0, _block.length);
+ System.arraycopy(originalDigest._state, 0, _state, 0, _state.length);
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/ec/ECPair.java b/src/main/java/org/bouncycastle/crypto/ec/ECPair.java
index 8f868dec..d910f3c7 100644
--- a/src/main/java/org/bouncycastle/crypto/ec/ECPair.java
+++ b/src/main/java/org/bouncycastle/crypto/ec/ECPair.java
@@ -22,4 +22,17 @@ public class ECPair
{
return y;
}
+
+ public byte[] getEncoded()
+ {
+ byte[] xEnc = x.getEncoded();
+ byte[] yEnc = y.getEncoded();
+
+ byte[] full = new byte[xEnc.length + yEnc.length];
+
+ System.arraycopy(xEnc, 0, full, 0, xEnc.length);
+ System.arraycopy(yEnc, 0, full, xEnc.length, yEnc.length);
+
+ return full;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java b/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
index f6941e3c..513eccdf 100644
--- a/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
@@ -47,21 +47,7 @@ public class DESedeEngine
if (keyMaster.length != 24 && keyMaster.length != 16)
{
- // new style 3TDEA key without parity bits.
- if (keyMaster.length == 21)
- {
- byte[] tmp = new byte[24];
-
- padKey(keyMaster, 0, tmp, 0);
- padKey(keyMaster, 7, tmp, 8);
- padKey(keyMaster, 14, tmp, 16);
-
- keyMaster = tmp;
- }
- else
- {
- throw new IllegalArgumentException("key size must be 16, 21, or 24 bytes.");
- }
+ throw new IllegalArgumentException("key size must be 16 or 24 bytes.");
}
this.forEncryption = encrypting;
@@ -86,18 +72,6 @@ public class DESedeEngine
}
}
- private void padKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
- {
- tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
- tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >>> 1));
- tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >>> 2));
- tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >>> 3));
- tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >>> 4));
- tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >>> 5));
- tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >>> 6));
- tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
- }
-
public String getAlgorithmName()
{
return "DESede";
diff --git a/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java b/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
index f77d5f56..ea8556de 100755
--- a/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
@@ -1,398 +1,398 @@
-package org.bouncycastle.crypto.engines;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.crypto.BasicAgreement;
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.EphemeralKeyPair;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.KeyParser;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.IESParameters;
-import org.bouncycastle.crypto.params.IESWithCipherParameters;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.util.Pack;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.BigIntegers;
-
-/**
- * Support class for constructing integrated encryption ciphers
- * for doing basic message exchanges on top of key agreement ciphers.
- * Follows the description given in IEEE Std 1363a.
- */
-public class IESEngine
-{
- BasicAgreement agree;
- DerivationFunction kdf;
- Mac mac;
- BufferedBlockCipher cipher;
- byte[] macBuf;
-
- boolean forEncryption;
- CipherParameters privParam, pubParam;
- IESParameters param;
-
- byte[] V;
- private EphemeralKeyPairGenerator keyPairGenerator;
- private KeyParser keyParser;
-
-
- /**
- * set up for use with stream mode, where the key derivation function
- * is used to provide a stream of bytes to xor with the message.
- *
- * @param agree the key agreement used as the basis for the encryption
- * @param kdf the key derivation function used for byte generation
- * @param mac the message authentication code generator for the message
- */
- public IESEngine(
- BasicAgreement agree,
- DerivationFunction kdf,
- Mac mac)
- {
- this.agree = agree;
- this.kdf = kdf;
- this.mac = mac;
- this.macBuf = new byte[mac.getMacSize()];
- this.cipher = null;
- }
-
-
- /**
- * set up for use in conjunction with a block cipher to handle the
- * message.
- *
- * @param agree the key agreement used as the basis for the encryption
- * @param kdf the key derivation function used for byte generation
- * @param mac the message authentication code generator for the message
- * @param cipher the cipher to used for encrypting the message
- */
- public IESEngine(
- BasicAgreement agree,
- DerivationFunction kdf,
- Mac mac,
- BufferedBlockCipher cipher)
- {
- this.agree = agree;
- this.kdf = kdf;
- this.mac = mac;
- this.macBuf = new byte[mac.getMacSize()];
- this.cipher = cipher;
- }
-
-
- /**
- * Initialise the encryptor.
- *
- * @param forEncryption whether or not this is encryption/decryption.
- * @param privParam our private key parameters
- * @param pubParam the recipient's/sender's public key parameters
- * @param param encoding and derivation parameters.
- */
- public void init(
- boolean forEncryption,
- CipherParameters privParam,
- CipherParameters pubParam,
- CipherParameters param)
- {
- this.forEncryption = forEncryption;
- this.privParam = privParam;
- this.pubParam = pubParam;
- this.param = (IESParameters)param;
- this.V = new byte[0];
- }
-
-
- /**
- * Initialise the encryptor.
- *
- * @param publicKey the recipient's/sender's public key parameters
- * @param params encoding and derivation parameters.
- * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use.
- */
- public void init(AsymmetricKeyParameter publicKey, CipherParameters params, EphemeralKeyPairGenerator ephemeralKeyPairGenerator)
- {
- this.forEncryption = true;
- this.pubParam = publicKey;
- this.param = (IESParameters)params;
- this.keyPairGenerator = ephemeralKeyPairGenerator;
- }
-
- /**
- * Initialise the encryptor.
- *
- * @param privateKey the recipient's private key.
- * @param params encoding and derivation parameters.
- * @param publicKeyParser the parser for reading the ephemeral public key.
- */
- public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser)
- {
- this.forEncryption = false;
- this.privParam = privateKey;
- this.param = (IESParameters)params;
- this.keyParser = publicKeyParser;
- }
-
- public BufferedBlockCipher getCipher()
- {
- return cipher;
- }
-
- public Mac getMac()
- {
- return mac;
- }
-
- private byte[] encryptBlock(
- byte[] in,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- byte[] C = null, K = null, K1 = null, K2 = null;
- int len;
-
- if (cipher == null)
- {
- // Streaming mode.
- K1 = new byte[inLen];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
-
- if (V.length != 0)
- {
- System.arraycopy(K, 0, K2, 0, K2.length);
- System.arraycopy(K, K2.length, K1, 0, K1.length);
- }
- else
- {
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, inLen, K2, 0, K2.length);
- }
-
- C = new byte[inLen];
-
- for (int i = 0; i != inLen; i++)
- {
- C[i] = (byte)(in[inOff + i] ^ K1[i]);
- }
- len = inLen;
- }
- else
- {
- // Block cipher mode.
- K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
-
- cipher.init(true, new KeyParameter(K1));
- C = new byte[cipher.getOutputSize(inLen)];
- len = cipher.processBytes(in, inOff, inLen, C, 0);
- len += cipher.doFinal(C, len);
- }
-
-
- // Convert the length of the encoding vector into a byte array.
- byte[] P2 = param.getEncodingV();
- byte[] L2 = new byte[4];
- if (V.length != 0 && P2 != null)
- {
- Pack.intToBigEndian(P2.length * 8, L2, 0);
- }
-
-
- // Apply the MAC.
- byte[] T = new byte[mac.getMacSize()];
-
- mac.init(new KeyParameter(K2));
- mac.update(C, 0, C.length);
- if (P2 != null)
- {
- mac.update(P2, 0, P2.length);
- }
- if (V.length != 0)
- {
- mac.update(L2, 0, L2.length);
- }
- mac.doFinal(T, 0);
-
-
- // Output the triple (V,C,T).
- byte[] Output = new byte[V.length + len + T.length];
- System.arraycopy(V, 0, Output, 0, V.length);
- System.arraycopy(C, 0, Output, V.length, len);
- System.arraycopy(T, 0, Output, V.length + len, T.length);
- return Output;
- }
-
- private byte[] decryptBlock(
- byte[] in_enc,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- byte[] M = null, K = null, K1 = null, K2 = null;
- int len;
-
- if (cipher == null)
- {
- // Streaming mode.
- K1 = new byte[inLen - V.length - mac.getMacSize()];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
-
- if (V.length != 0)
- {
- System.arraycopy(K, 0, K2, 0, K2.length);
- System.arraycopy(K, K2.length, K1, 0, K1.length);
- }
- else
- {
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
- }
-
- M = new byte[K1.length];
-
- for (int i = 0; i != K1.length; i++)
- {
- M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]);
- }
-
- len = K1.length;
- }
- else
- {
- // Block cipher mode.
- K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
-
- cipher.init(false, new KeyParameter(K1));
-
- M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())];
- len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0);
- len += cipher.doFinal(M, len);
- }
-
-
- // Convert the length of the encoding vector into a byte array.
- byte[] P2 = param.getEncodingV();
- byte[] L2 = new byte[4];
- if (V.length != 0 && P2 != null)
- {
- Pack.intToBigEndian(P2.length * 8, L2, 0);
- }
-
-
- // Verify the MAC.
- int end = inOff + inLen;
- byte[] T1 = Arrays.copyOfRange(in_enc, end - mac.getMacSize(), end);
-
- byte[] T2 = new byte[T1.length];
- mac.init(new KeyParameter(K2));
- mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length);
-
- if (P2 != null)
- {
- mac.update(P2, 0, P2.length);
- }
- if (V.length != 0)
- {
- mac.update(L2, 0, L2.length);
- }
- mac.doFinal(T2, 0);
-
- if (!Arrays.constantTimeAreEqual(T1, T2))
- {
- throw new InvalidCipherTextException("Invalid MAC.");
- }
-
-
- // Output the message.
- return Arrays.copyOfRange(M, 0, len);
- }
-
-
- public byte[] processBlock(
- byte[] in,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- if (forEncryption)
- {
- if (keyPairGenerator != null)
- {
- EphemeralKeyPair ephKeyPair = keyPairGenerator.generate();
-
- this.privParam = ephKeyPair.getKeyPair().getPrivate();
- this.V = ephKeyPair.getEncodedPublicKey();
- }
- }
- else
- {
- if (keyParser != null)
- {
- ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen);
-
- try
- {
- this.pubParam = keyParser.readKey(bIn);
- }
- catch (IOException e)
- {
- throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
- }
-
- int encLength = (inLen - bIn.available());
- this.V = Arrays.copyOfRange(in, inOff, inOff + encLength);
- }
- }
-
- // Compute the common value and convert to byte array.
- agree.init(privParam);
- BigInteger z = agree.calculateAgreement(pubParam);
- byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z);
-
- // Create input to KDF.
- byte[] VZ;
- if (V.length != 0)
- {
- VZ = new byte[V.length + Z.length];
- System.arraycopy(V, 0, VZ, 0, V.length);
- System.arraycopy(Z, 0, VZ, V.length, Z.length);
- }
- else
- {
- VZ = Z;
- }
-
- // Initialise the KDF.
- KDFParameters kdfParam = new KDFParameters(VZ, param.getDerivationV());
- kdf.init(kdfParam);
-
- return forEncryption
- ? encryptBlock(in, inOff, inLen)
- : decryptBlock(in, inOff, inLen);
- }
-}
+package org.bouncycastle.crypto.engines;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.EphemeralKeyPair;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.KeyParser;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.IESParameters;
+import org.bouncycastle.crypto.params.IESWithCipherParameters;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * Support class for constructing integrated encryption ciphers
+ * for doing basic message exchanges on top of key agreement ciphers.
+ * Follows the description given in IEEE Std 1363a.
+ */
+public class IESEngine
+{
+ BasicAgreement agree;
+ DerivationFunction kdf;
+ Mac mac;
+ BufferedBlockCipher cipher;
+ byte[] macBuf;
+
+ boolean forEncryption;
+ CipherParameters privParam, pubParam;
+ IESParameters param;
+
+ byte[] V;
+ private EphemeralKeyPairGenerator keyPairGenerator;
+ private KeyParser keyParser;
+
+
+ /**
+ * set up for use with stream mode, where the key derivation function
+ * is used to provide a stream of bytes to xor with the message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ */
+ public IESEngine(
+ BasicAgreement agree,
+ DerivationFunction kdf,
+ Mac mac)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.getMacSize()];
+ this.cipher = null;
+ }
+
+
+ /**
+ * set up for use in conjunction with a block cipher to handle the
+ * message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ * @param cipher the cipher to used for encrypting the message
+ */
+ public IESEngine(
+ BasicAgreement agree,
+ DerivationFunction kdf,
+ Mac mac,
+ BufferedBlockCipher cipher)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.getMacSize()];
+ this.cipher = cipher;
+ }
+
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param forEncryption whether or not this is encryption/decryption.
+ * @param privParam our private key parameters
+ * @param pubParam the recipient's/sender's public key parameters
+ * @param param encoding and derivation parameters.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters privParam,
+ CipherParameters pubParam,
+ CipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ this.privParam = privParam;
+ this.pubParam = pubParam;
+ this.param = (IESParameters)param;
+ this.V = new byte[0];
+ }
+
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param publicKey the recipient's/sender's public key parameters
+ * @param params encoding and derivation parameters.
+ * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use.
+ */
+ public void init(AsymmetricKeyParameter publicKey, CipherParameters params, EphemeralKeyPairGenerator ephemeralKeyPairGenerator)
+ {
+ this.forEncryption = true;
+ this.pubParam = publicKey;
+ this.param = (IESParameters)params;
+ this.keyPairGenerator = ephemeralKeyPairGenerator;
+ }
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param privateKey the recipient's private key.
+ * @param params encoding and derivation parameters.
+ * @param publicKeyParser the parser for reading the ephemeral public key.
+ */
+ public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser)
+ {
+ this.forEncryption = false;
+ this.privParam = privateKey;
+ this.param = (IESParameters)params;
+ this.keyParser = publicKeyParser;
+ }
+
+ public BufferedBlockCipher getCipher()
+ {
+ return cipher;
+ }
+
+ public Mac getMac()
+ {
+ return mac;
+ }
+
+ private byte[] encryptBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] C = null, K = null, K1 = null, K2 = null;
+ int len;
+
+ if (cipher == null)
+ {
+ // Streaming mode.
+ K1 = new byte[inLen];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+
+ if (V.length != 0)
+ {
+ System.arraycopy(K, 0, K2, 0, K2.length);
+ System.arraycopy(K, K2.length, K1, 0, K1.length);
+ }
+ else
+ {
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, inLen, K2, 0, K2.length);
+ }
+
+ C = new byte[inLen];
+
+ for (int i = 0; i != inLen; i++)
+ {
+ C[i] = (byte)(in[inOff + i] ^ K1[i]);
+ }
+ len = inLen;
+ }
+ else
+ {
+ // Block cipher mode.
+ K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+
+ cipher.init(true, new KeyParameter(K1));
+ C = new byte[cipher.getOutputSize(inLen)];
+ len = cipher.processBytes(in, inOff, inLen, C, 0);
+ len += cipher.doFinal(C, len);
+ }
+
+
+ // Convert the length of the encoding vector into a byte array.
+ byte[] P2 = param.getEncodingV();
+ byte[] L2 = new byte[4];
+ if (V.length != 0 && P2 != null)
+ {
+ Pack.intToBigEndian(P2.length * 8, L2, 0);
+ }
+
+
+ // Apply the MAC.
+ byte[] T = new byte[mac.getMacSize()];
+
+ mac.init(new KeyParameter(K2));
+ mac.update(C, 0, C.length);
+ if (P2 != null)
+ {
+ mac.update(P2, 0, P2.length);
+ }
+ if (V.length != 0)
+ {
+ mac.update(L2, 0, L2.length);
+ }
+ mac.doFinal(T, 0);
+
+
+ // Output the triple (V,C,T).
+ byte[] Output = new byte[V.length + len + T.length];
+ System.arraycopy(V, 0, Output, 0, V.length);
+ System.arraycopy(C, 0, Output, V.length, len);
+ System.arraycopy(T, 0, Output, V.length + len, T.length);
+ return Output;
+ }
+
+ private byte[] decryptBlock(
+ byte[] in_enc,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] M = null, K = null, K1 = null, K2 = null;
+ int len;
+
+ if (cipher == null)
+ {
+ // Streaming mode.
+ K1 = new byte[inLen - V.length - mac.getMacSize()];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+
+ if (V.length != 0)
+ {
+ System.arraycopy(K, 0, K2, 0, K2.length);
+ System.arraycopy(K, K2.length, K1, 0, K1.length);
+ }
+ else
+ {
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+ }
+
+ M = new byte[K1.length];
+
+ for (int i = 0; i != K1.length; i++)
+ {
+ M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]);
+ }
+
+ len = K1.length;
+ }
+ else
+ {
+ // Block cipher mode.
+ K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
+ K2 = new byte[param.getMacKeySize() / 8];
+ K = new byte[K1.length + K2.length];
+
+ kdf.generateBytes(K, 0, K.length);
+ System.arraycopy(K, 0, K1, 0, K1.length);
+ System.arraycopy(K, K1.length, K2, 0, K2.length);
+
+ cipher.init(false, new KeyParameter(K1));
+
+ M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())];
+ len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0);
+ len += cipher.doFinal(M, len);
+ }
+
+
+ // Convert the length of the encoding vector into a byte array.
+ byte[] P2 = param.getEncodingV();
+ byte[] L2 = new byte[4];
+ if (V.length != 0 && P2 != null)
+ {
+ Pack.intToBigEndian(P2.length * 8, L2, 0);
+ }
+
+
+ // Verify the MAC.
+ int end = inOff + inLen;
+ byte[] T1 = Arrays.copyOfRange(in_enc, end - mac.getMacSize(), end);
+
+ byte[] T2 = new byte[T1.length];
+ mac.init(new KeyParameter(K2));
+ mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length);
+
+ if (P2 != null)
+ {
+ mac.update(P2, 0, P2.length);
+ }
+ if (V.length != 0)
+ {
+ mac.update(L2, 0, L2.length);
+ }
+ mac.doFinal(T2, 0);
+
+ if (!Arrays.constantTimeAreEqual(T1, T2))
+ {
+ throw new InvalidCipherTextException("Invalid MAC.");
+ }
+
+
+ // Output the message.
+ return Arrays.copyOfRange(M, 0, len);
+ }
+
+
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forEncryption)
+ {
+ if (keyPairGenerator != null)
+ {
+ EphemeralKeyPair ephKeyPair = keyPairGenerator.generate();
+
+ this.privParam = ephKeyPair.getKeyPair().getPrivate();
+ this.V = ephKeyPair.getEncodedPublicKey();
+ }
+ }
+ else
+ {
+ if (keyParser != null)
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen);
+
+ try
+ {
+ this.pubParam = keyParser.readKey(bIn);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
+ }
+
+ int encLength = (inLen - bIn.available());
+ this.V = Arrays.copyOfRange(in, inOff, inOff + encLength);
+ }
+ }
+
+ // Compute the common value and convert to byte array.
+ agree.init(privParam);
+ BigInteger z = agree.calculateAgreement(pubParam);
+ byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z);
+
+ // Create input to KDF.
+ byte[] VZ;
+ if (V.length != 0)
+ {
+ VZ = new byte[V.length + Z.length];
+ System.arraycopy(V, 0, VZ, 0, V.length);
+ System.arraycopy(Z, 0, VZ, V.length, Z.length);
+ }
+ else
+ {
+ VZ = Z;
+ }
+
+ // Initialise the KDF.
+ KDFParameters kdfParam = new KDFParameters(VZ, param.getDerivationV());
+ kdf.init(kdfParam);
+
+ return forEncryption
+ ? encryptBlock(in, inOff, inLen)
+ : decryptBlock(in, inOff, inLen);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
index c6e39986..2ef8dd2b 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
@@ -1,142 +1,142 @@
-package org.bouncycastle.crypto.generators;
-
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.ISO18033KDFParameters;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO
- * 18033 <br>
- * This implementation is based on ISO 18033/P1363a.
- */
-public class BaseKDFBytesGenerator implements DerivationFunction
-{
- private int counterStart;
- private Digest digest;
- private byte[] shared;
- private byte[] iv;
-
- /**
- * Construct a KDF Parameters generator.
- * <p>
- *
- * @param counterStart
- * value of counter.
- * @param digest
- * the digest to be used as the source of derived keys.
- */
- protected BaseKDFBytesGenerator(int counterStart, Digest digest)
- {
- this.counterStart = counterStart;
- this.digest = digest;
- }
-
- public void init(DerivationParameters param)
- {
- if (param instanceof KDFParameters)
- {
- KDFParameters p = (KDFParameters)param;
-
- shared = p.getSharedSecret();
- iv = p.getIV();
- }
- else if (param instanceof ISO18033KDFParameters)
- {
- ISO18033KDFParameters p = (ISO18033KDFParameters)param;
-
- shared = p.getSeed();
- iv = null;
- }
- else
- {
- throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
- }
- }
-
- /**
- * return the underlying digest.
- */
- public Digest getDigest()
- {
- return digest;
- }
-
- /**
- * fill len bytes of the output buffer with bytes generated from the
- * derivation function.
- *
- * @throws IllegalArgumentException
- * if the size of the request will cause an overflow.
- * @throws DataLengthException
- * if the out buffer is too small.
- */
- public int generateBytes(byte[] out, int outOff, int len) throws DataLengthException,
- IllegalArgumentException
- {
- if ((out.length - len) < outOff)
- {
- throw new DataLengthException("output buffer too small");
- }
-
- long oBytes = len;
- int outLen = digest.getDigestSize();
-
- //
- // this is at odds with the standard implementation, the
- // maximum value should be hBits * (2^32 - 1) where hBits
- // is the digest output size in bits. We can't have an
- // array with a long index at the moment...
- //
- if (oBytes > ((2L << 32) - 1))
- {
- throw new IllegalArgumentException("Output length too large");
- }
-
- int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
- byte[] dig = new byte[digest.getDigestSize()];
-
- byte[] C = new byte[4];
- Pack.intToBigEndian(counterStart, C, 0);
-
- int counterBase = counterStart & ~0xFF;
-
- for (int i = 0; i < cThreshold; i++)
- {
- digest.update(shared, 0, shared.length);
- digest.update(C, 0, C.length);
-
- if (iv != null)
- {
- digest.update(iv, 0, iv.length);
- }
-
- digest.doFinal(dig, 0);
-
- if (len > outLen)
- {
- System.arraycopy(dig, 0, out, outOff, outLen);
- outOff += outLen;
- len -= outLen;
- }
- else
- {
- System.arraycopy(dig, 0, out, outOff, len);
- }
-
- if (++C[3] == 0)
- {
- counterBase += 0x100;
- Pack.intToBigEndian(counterBase, C, 0);
- }
- }
-
- digest.reset();
-
- return (int)oBytes;
- }
-}
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.params.ISO18033KDFParameters;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.util.Pack;
+
+/**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO
+ * 18033 <br>
+ * This implementation is based on ISO 18033/P1363a.
+ */
+public class BaseKDFBytesGenerator implements DerivationFunction
+{
+ private int counterStart;
+ private Digest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF Parameters generator.
+ * <p>
+ *
+ * @param counterStart
+ * value of counter.
+ * @param digest
+ * the digest to be used as the source of derived keys.
+ */
+ protected BaseKDFBytesGenerator(int counterStart, Digest digest)
+ {
+ this.counterStart = counterStart;
+ this.digest = digest;
+ }
+
+ public void init(DerivationParameters param)
+ {
+ if (param instanceof KDFParameters)
+ {
+ KDFParameters p = (KDFParameters)param;
+
+ shared = p.getSharedSecret();
+ iv = p.getIV();
+ }
+ else if (param instanceof ISO18033KDFParameters)
+ {
+ ISO18033KDFParameters p = (ISO18033KDFParameters)param;
+
+ shared = p.getSeed();
+ iv = null;
+ }
+ else
+ {
+ throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ }
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from the
+ * derivation function.
+ *
+ * @throws IllegalArgumentException
+ * if the size of the request will cause an overflow.
+ * @throws DataLengthException
+ * if the out buffer is too small.
+ */
+ public int generateBytes(byte[] out, int outOff, int len) throws DataLengthException,
+ IllegalArgumentException
+ {
+ if ((out.length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = len;
+ int outLen = digest.getDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new IllegalArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.getDigestSize()];
+
+ byte[] C = new byte[4];
+ Pack.intToBigEndian(counterStart, C, 0);
+
+ int counterBase = counterStart & ~0xFF;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.update(shared, 0, shared.length);
+ digest.update(C, 0, C.length);
+
+ if (iv != null)
+ {
+ digest.update(iv, 0, iv.length);
+ }
+
+ digest.doFinal(dig, 0);
+
+ if (len > outLen)
+ {
+ System.arraycopy(dig, 0, out, outOff, outLen);
+ outOff += outLen;
+ len -= outLen;
+ }
+ else
+ {
+ System.arraycopy(dig, 0, out, outOff, len);
+ }
+
+ if (++C[3] == 0)
+ {
+ counterBase += 0x100;
+ Pack.intToBigEndian(counterBase, C, 0);
+ }
+ }
+
+ digest.reset();
+
+ return (int)oBytes;
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index be977d71..749b0cc5 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -1,22 +1,23 @@
package org.bouncycastle.crypto.generators;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAValidationParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.encoders.Hex;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
-// TODO Update javadoc to mention FIPS 186-3 when done
/**
- * generate suitable parameters for DSA, in line with FIPS 186-2.
+ * Generate suitable parameters for DSA, in line with FIPS 186-2, or FIPS 186-3.
*/
public class DSAParametersGenerator
{
+ private Digest digest;
private int L, N;
private int certainty;
private SecureRandom random;
@@ -25,6 +26,19 @@ public class DSAParametersGenerator
private static final BigInteger ONE = BigInteger.valueOf(1);
private static final BigInteger TWO = BigInteger.valueOf(2);
+ private boolean use186_3;
+ private int usageIndex;
+
+ public DSAParametersGenerator()
+ {
+ this(new SHA1Digest());
+ }
+
+ public DSAParametersGenerator(Digest digest)
+ {
+ this.digest = digest;
+ }
+
/**
* initialise the key generator.
*
@@ -37,23 +51,53 @@ public class DSAParametersGenerator
int certainty,
SecureRandom random)
{
- init(size, getDefaultN(size), certainty, random);
+ this.use186_3 = false;
+ this.L = size;
+ this.N = getDefaultN(size);
+ this.certainty = certainty;
+ this.random = random;
}
- // TODO Make public to enable support for DSA keys > 1024 bits
- private void init(
- int L,
- int N,
- int certainty,
- SecureRandom random)
+ /**
+ * Initialise the key generator for DSA 2.
+ * <p>
+ * Use this init method if you need to generate parameters for DSA 2 keys.
+ * </p>
+ *
+ * @param params DSA 2 key generation parameters.
+ */
+ public void init(
+ DSAParameterGenerationParameters params)
{
- // TODO Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2)
// TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+ this.use186_3 = true;
+ this.L = params.getL();
+ this.N = params.getN();
+ this.certainty = params.getCertainty();
+ this.random = params.getRandom();
+ this.usageIndex = params.getUsageIndex();
+
+ if ((L < 1024 || L > 3072) || L % 1024 != 0)
+ {
+ throw new IllegalArgumentException("L values must be between 1024 and 3072 and a multiple of 1024");
+ }
+ else if (L == 1024 && N != 160)
+ {
+ throw new IllegalArgumentException("N must be 160 for L = 1024");
+ }
+ else if (L == 2048 && (N != 224 && N != 256))
+ {
+ throw new IllegalArgumentException("N must be 224 or 256 for L = 2048");
+ }
+ else if (L == 3072 && N != 256)
+ {
+ throw new IllegalArgumentException("N must be 256 for L = 3072");
+ }
- this.L = L;
- this.N = N;
- this.certainty = certainty;
- this.random = random;
+ if (digest.getDigestSize() * 8 < N)
+ {
+ throw new IllegalStateException("Digest output size too small for value of N");
+ }
}
/**
@@ -64,7 +108,7 @@ public class DSAParametersGenerator
*/
public DSAParameters generateParameters()
{
- return L > 1024
+ return (use186_3)
? generateParameters_FIPS186_3()
: generateParameters_FIPS186_2();
}
@@ -75,18 +119,22 @@ public class DSAParametersGenerator
byte[] part1 = new byte[20];
byte[] part2 = new byte[20];
byte[] u = new byte[20];
- SHA1Digest sha1 = new SHA1Digest();
int n = (L - 1) / 160;
byte[] w = new byte[L / 8];
+ if (!(digest instanceof SHA1Digest))
+ {
+ throw new IllegalStateException("can only use SHA-1 for generating FIPS 186-2 parameters");
+ }
+
for (;;)
{
random.nextBytes(seed);
- hash(sha1, seed, part1);
+ hash(digest, seed, part1);
System.arraycopy(seed, 0, part2, 0, seed.length);
inc(part2);
- hash(sha1, part2, part2);
+ hash(digest, part2, part2);
for (int i = 0; i != u.length; i++)
{
@@ -111,12 +159,12 @@ public class DSAParametersGenerator
for (int k = 0; k < n; k++)
{
inc(offset);
- hash(sha1, offset, part1);
+ hash(digest, offset, part1);
System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, part1.length);
}
inc(offset);
- hash(sha1, offset, part1);
+ hash(digest, offset, part1);
System.arraycopy(part1, part1.length - ((w.length - (n) * part1.length)), w, 0, w.length - n * part1.length);
w[0] |= (byte)0x80;
@@ -166,7 +214,7 @@ public class DSAParametersGenerator
{
// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
// FIXME This should be configurable (digest size in bits must be >= N)
- Digest d = new SHA256Digest();
+ Digest d = digest;
int outlen = d.getDigestSize() * 8;
// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
@@ -192,6 +240,7 @@ public class DSAParametersGenerator
// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
hash(d, seed, output);
+
BigInteger U = new BigInteger(1, output).mod(ONE.shiftLeft(N - 1));
// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
@@ -253,16 +302,17 @@ public class DSAParametersGenerator
{
// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
// (optionally) the values of domain_parameter_seed and counter.
- // TODO Make configurable (8-bit unsigned)?
-// int index = 1;
-// BigInteger g = calculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, index);
-// if (g != null)
-// {
-// // TODO Should 'index' be a part of the validation parameters?
-// return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
-// }
+ if (usageIndex >= 0)
+ {
+ BigInteger g = calculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, usageIndex);
+ if (g != null)
+ {
+ return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter, usageIndex));
+ }
+ }
BigInteger g = calculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+
return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
}
@@ -281,34 +331,34 @@ public class DSAParametersGenerator
return calculateGenerator_FIPS186_2(p, q, r);
}
-// private static BigInteger calculateGenerator_FIPS186_3_Verifiable(Digest d, BigInteger p, BigInteger q,
-// byte[] seed, int index)
-// {
-//// A.2.3 Verifiable Canonical Generation of the Generator g
-// BigInteger e = p.subtract(ONE).divide(q);
-// byte[] ggen = Hex.decode("6767656E");
-//
-// // 7. U = domain_parameter_seed || "ggen" || index || count.
-// byte[] U = new byte[seed.length + ggen.length + 1 + 2];
-// System.arraycopy(seed, 0, U, 0, seed.length);
-// System.arraycopy(ggen, 0, U, seed.length, ggen.length);
-// U[U.length - 3] = (byte)index;
-//
-// byte[] w = new byte[d.getDigestSize()];
-// for (int count = 1; count < (1 << 16); ++count)
-// {
-// inc(U);
-// hash(d, U, w);
-// BigInteger W = new BigInteger(1, w);
-// BigInteger g = W.modPow(e, p);
-// if (g.compareTo(TWO) >= 0)
-// {
-// return g;
-// }
-// }
-//
-// return null;
-// }
+ private static BigInteger calculateGenerator_FIPS186_3_Verifiable(Digest d, BigInteger p, BigInteger q,
+ byte[] seed, int index)
+ {
+// A.2.3 Verifiable Canonical Generation of the Generator g
+ BigInteger e = p.subtract(ONE).divide(q);
+ byte[] ggen = Hex.decode("6767656E");
+
+ // 7. U = domain_parameter_seed || "ggen" || index || count.
+ byte[] U = new byte[seed.length + ggen.length + 1 + 2];
+ System.arraycopy(seed, 0, U, 0, seed.length);
+ System.arraycopy(ggen, 0, U, seed.length, ggen.length);
+ U[U.length - 3] = (byte)index;
+
+ byte[] w = new byte[d.getDigestSize()];
+ for (int count = 1; count < (1 << 16); ++count)
+ {
+ inc(U);
+ hash(d, U, w);
+ BigInteger W = new BigInteger(1, w);
+ BigInteger g = W.modPow(e, p);
+ if (g.compareTo(TWO) >= 0)
+ {
+ return g;
+ }
+ }
+
+ return null;
+ }
private static void hash(Digest d, byte[] input, byte[] output)
{
diff --git a/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java b/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
new file mode 100755
index 00000000..7332f264
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
@@ -0,0 +1,254 @@
+package org.bouncycastle.crypto.kems;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.KeyEncapsulation;
+import org.bouncycastle.crypto.params.ECKeyParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * The ECIES Key Encapsulation Mechanism (ECIES-KEM) from ISO 18033-2.
+ */
+public class ECIESKeyEncapsulation
+ implements KeyEncapsulation
+{
+ private DerivationFunction kdf;
+ private SecureRandom rnd;
+ private ECKeyParameters key;
+ private boolean CofactorMode;
+ private boolean OldCofactorMode;
+ private boolean SingleHashMode;
+
+ /**
+ * Set up the ECIES-KEM.
+ *
+ * @param kdf the key derivation function to be used.
+ * @param rnd the random source for the session key.
+ */
+ public ECIESKeyEncapsulation(
+ DerivationFunction kdf,
+ SecureRandom rnd)
+ {
+ this.kdf = kdf;
+ this.rnd = rnd;
+ this.CofactorMode = false;
+ this.OldCofactorMode = false;
+ this.SingleHashMode = false;
+ }
+
+ /**
+ * Set up the ECIES-KEM.
+ *
+ * @param kdf the key derivation function to be used.
+ * @param rnd the random source for the session key.
+ * @param cofactorMode true to use the new cofactor ECDH.
+ * @param oldCofactorMode true to use the old cofactor ECDH.
+ * @param singleHashMode true to use single hash mode.
+ */
+ public ECIESKeyEncapsulation(
+ DerivationFunction kdf,
+ SecureRandom rnd,
+ boolean cofactorMode,
+ boolean oldCofactorMode,
+ boolean singleHashMode)
+ {
+ this.kdf = kdf;
+ this.rnd = rnd;
+
+ // If both cofactorMode and oldCofactorMode are set to true
+ // then the implementation will use the new cofactor ECDH
+ this.CofactorMode = cofactorMode;
+ this.OldCofactorMode = oldCofactorMode;
+ this.SingleHashMode = singleHashMode;
+ }
+
+ /**
+ * Initialise the ECIES-KEM.
+ *
+ * @param key the recipient's public (for encryption) or private (for decryption) key.
+ */
+ public void init(CipherParameters key)
+ throws IllegalArgumentException
+ {
+ if (!(key instanceof ECKeyParameters))
+ {
+ throw new IllegalArgumentException("EC key required");
+ }
+ else
+ {
+ this.key = (ECKeyParameters)key;
+ }
+ }
+
+ /**
+ * Generate and encapsulate a random session key.
+ *
+ * @param out the output buffer for the encapsulated key.
+ * @param outOff the offset for the output buffer.
+ * @param keyLen the length of the session key.
+ * @return the random session key.
+ */
+ public CipherParameters encrypt(byte[] out, int outOff, int keyLen)
+ throws IllegalArgumentException
+ {
+ if (!(key instanceof ECPublicKeyParameters))
+ {
+ throw new IllegalArgumentException("Public key required for encryption");
+ }
+
+ BigInteger n = key.getParameters().getN();
+ BigInteger h = key.getParameters().getH();
+
+ // Generate the ephemeral key pair
+ BigInteger r = BigIntegers.createRandomInRange(BigInteger.ONE, n, rnd);
+ ECPoint gTilde = key.getParameters().getG().multiply(r);
+
+ // Encode the ephemeral public key
+ byte[] C = gTilde.getEncoded();
+ System.arraycopy(C, 0, out, outOff, C.length);
+
+ // Compute the static-ephemeral key agreement
+ BigInteger rPrime;
+ if (CofactorMode)
+ {
+ rPrime = r.multiply(h).mod(n);
+ }
+ else
+ {
+ rPrime = r;
+ }
+
+ ECPoint hTilde = ((ECPublicKeyParameters) key).getQ().multiply(rPrime);
+
+ // Encode the shared secret value
+ int PEHlen = (key.getParameters().getCurve().getFieldSize()+7)/8;
+ byte[] PEH = BigIntegers.asUnsignedByteArray(PEHlen, hTilde.getX().toBigInteger());
+
+ // Initialise the KDF
+ byte[] kdfInput;
+ if (SingleHashMode)
+ {
+ kdfInput = new byte[C.length + PEH.length];
+ System.arraycopy(C, 0, kdfInput, 0, C.length);
+ System.arraycopy(PEH, 0, kdfInput, C.length, PEH.length);
+ }
+ else
+ {
+ kdfInput = PEH;
+ }
+
+ kdf.init(new KDFParameters(kdfInput, null));
+
+ // Generate the secret key
+ byte[] K = new byte[keyLen];
+ kdf.generateBytes(K, 0, K.length);
+
+ // Return the ciphertext
+ return new KeyParameter(K);
+ }
+
+ /**
+ * Generate and encapsulate a random session key.
+ *
+ * @param out the output buffer for the encapsulated key.
+ * @param keyLen the length of the session key.
+ * @return the random session key.
+ */
+ public CipherParameters encrypt(byte[] out, int keyLen)
+ {
+ return encrypt(out, 0, keyLen);
+ }
+
+ /**
+ * Decrypt an encapsulated session key.
+ *
+ * @param in the input buffer for the encapsulated key.
+ * @param inOff the offset for the input buffer.
+ * @param inLen the length of the encapsulated key.
+ * @param keyLen the length of the session key.
+ * @return the session key.
+ */
+ public CipherParameters decrypt(byte[] in, int inOff, int inLen, int keyLen)
+ throws IllegalArgumentException
+ {
+ if (!(key instanceof ECPrivateKeyParameters))
+ {
+ throw new IllegalArgumentException("Private key required for encryption");
+ }
+
+ BigInteger n = key.getParameters().getN();
+ BigInteger h = key.getParameters().getH();
+
+ // Decode the ephemeral public key
+ byte[] C = new byte[inLen];
+ System.arraycopy(in, inOff, C, 0, inLen);
+ ECPoint gTilde = key.getParameters().getCurve().decodePoint(C);
+
+ // Compute the static-ephemeral key agreement
+ ECPoint gHat;
+ if ((CofactorMode) || (OldCofactorMode))
+ {
+ gHat = gTilde.multiply(h);
+ }
+ else
+ {
+ gHat = gTilde;
+ }
+
+ BigInteger xHat;
+ if(CofactorMode)
+ {
+ xHat = ((ECPrivateKeyParameters) key).getD().multiply(h.modInverse(n)).mod(n);
+ }
+ else
+ {
+ xHat = ((ECPrivateKeyParameters) key).getD();
+ }
+
+ ECPoint hTilde = gHat.multiply(xHat);
+
+ // Encode the shared secret value
+ int PEHlen = (key.getParameters().getCurve().getFieldSize()+7)/8;
+ byte[] PEH = BigIntegers.asUnsignedByteArray(PEHlen, hTilde.getX().toBigInteger());
+
+ // Initialise the KDF
+ byte[] kdfInput;
+ if (SingleHashMode)
+ {
+ kdfInput = new byte[C.length + PEH.length];
+ System.arraycopy(C, 0, kdfInput, 0, C.length);
+ System.arraycopy(PEH, 0, kdfInput, C.length, PEH.length);
+ }
+ else
+ {
+ kdfInput = PEH;
+ }
+ kdf.init(new KDFParameters(kdfInput, null));
+
+ // Generate the secret key
+ byte[] K = new byte[keyLen];
+ kdf.generateBytes(K, 0, K.length);
+
+ return new KeyParameter(K);
+ }
+
+ /**
+ * Decrypt an encapsulated session key.
+ *
+ * @param in the input buffer for the encapsulated key.
+ * @param keyLen the length of the session key.
+ * @return the session key.
+ */
+ public CipherParameters decrypt(byte[] in, int keyLen)
+ {
+ return decrypt(in, 0, in.length, keyLen);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/kems/RSAKeyEncapsulation.java b/src/main/java/org/bouncycastle/crypto/kems/RSAKeyEncapsulation.java
new file mode 100755
index 00000000..5ffd356a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/kems/RSAKeyEncapsulation.java
@@ -0,0 +1,161 @@
+package org.bouncycastle.crypto.kems;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.KeyEncapsulation;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * The RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2.
+ */
+public class RSAKeyEncapsulation
+ implements KeyEncapsulation
+{
+ private DerivationFunction kdf;
+ private SecureRandom rnd;
+ private RSAKeyParameters key;
+
+ /**
+ * Set up the RSA-KEM.
+ *
+ * @param kdf the key derivation function to be used.
+ * @param rnd the random source for the session key.
+ */
+ public RSAKeyEncapsulation(
+ DerivationFunction kdf,
+ SecureRandom rnd)
+ {
+ this.kdf = kdf;
+ this.rnd = rnd;
+ }
+
+
+ /**
+ * Initialise the RSA-KEM.
+ *
+ * @param key the recipient's public (for encryption) or private (for decryption) key.
+ */
+ public void init(CipherParameters key)
+ throws IllegalArgumentException
+ {
+ if (!(key instanceof RSAKeyParameters))
+ {
+ throw new IllegalArgumentException("RSA key required");
+ }
+ else
+ {
+ this.key = (RSAKeyParameters)key;
+ }
+ }
+
+
+ /**
+ * Generate and encapsulate a random session key.
+ *
+ * @param out the output buffer for the encapsulated key.
+ * @param outOff the offset for the output buffer.
+ * @param keyLen the length of the random session key.
+ * @return the random session key.
+ */
+ public CipherParameters encrypt(byte[] out, int outOff, int keyLen)
+ throws IllegalArgumentException
+ {
+ if (key.isPrivate())
+ {
+ throw new IllegalArgumentException("Public key required for encryption");
+ }
+
+ BigInteger n = key.getModulus();
+ BigInteger e = key.getExponent();
+
+ // Generate the ephemeral random and encode it
+ BigInteger r = BigIntegers.createRandomInRange(BigInteger.ZERO, n.subtract(BigInteger.ONE), rnd);
+ byte[] R = BigIntegers.asUnsignedByteArray((n.bitLength()+7)/8, r);
+
+ // Encrypt the random and encode it
+ BigInteger c = r.modPow(e, n);
+ byte[] C = BigIntegers.asUnsignedByteArray((n.bitLength()+7)/8, c);
+ System.arraycopy(C, 0, out, outOff, C.length);
+
+
+ // Initialise the KDF
+ kdf.init(new KDFParameters(R, null));
+
+ // Generate the secret key
+ byte[] K = new byte[keyLen];
+ kdf.generateBytes(K, 0, K.length);
+
+ return new KeyParameter(K);
+ }
+
+
+ /**
+ * Generate and encapsulate a random session key.
+ *
+ * @param out the output buffer for the encapsulated key.
+ * @param keyLen the length of the random session key.
+ * @return the random session key.
+ */
+ public CipherParameters encrypt(byte[] out, int keyLen)
+ {
+ return encrypt(out, 0, keyLen);
+ }
+
+
+ /**
+ * Decrypt an encapsulated session key.
+ *
+ * @param in the input buffer for the encapsulated key.
+ * @param inOff the offset for the input buffer.
+ * @param inLen the length of the encapsulated key.
+ * @param keyLen the length of the session key.
+ * @return the session key.
+ */
+ public CipherParameters decrypt(byte[] in, int inOff, int inLen, int keyLen)
+ throws IllegalArgumentException
+ {
+ if (!key.isPrivate())
+ {
+ throw new IllegalArgumentException("Private key required for decryption");
+ }
+
+ BigInteger n = key.getModulus();
+ BigInteger d = key.getExponent();
+
+ // Decode the input
+ byte[] C = new byte[inLen];
+ System.arraycopy(in, inOff, C, 0, C.length);
+ BigInteger c = new BigInteger(1, C);
+
+ // Decrypt the ephemeral random and encode it
+ BigInteger r = c.modPow(d, n);
+ byte[] R = BigIntegers.asUnsignedByteArray((n.bitLength()+7)/8, r);
+
+ // Initialise the KDF
+ kdf.init(new KDFParameters(R, null));
+
+ // Generate the secret key
+ byte[] K = new byte[keyLen];
+ kdf.generateBytes(K, 0, K.length);
+
+ return new KeyParameter(K);
+ }
+
+ /**
+ * Decrypt an encapsulated session key.
+ *
+ * @param in the input buffer for the encapsulated key.
+ * @param keyLen the length of the session key.
+ * @return the session key.
+ */
+ public CipherParameters decrypt(byte[] in, int keyLen)
+ {
+ return decrypt(in, 0, in.length, keyLen);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/macs/GMac.java b/src/main/java/org/bouncycastle/crypto/macs/GMac.java
new file mode 100644
index 00000000..91bfe13d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/macs/GMac.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.params.AEADParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+ * 800-38D.
+ * <p>
+ * GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+ * is processed as additional authenticated data with the underlying GCM block cipher).
+ */
+public class GMac implements Mac
+{
+ private final GCMBlockCipher cipher;
+ private final int macSizeBits;
+
+ /**
+ * Creates a GMAC based on the operation of a block cipher in GCM mode.
+ * <p/>
+ * This will produce an authentication code the length of the block size of the cipher.
+ *
+ * @param cipher
+ * the cipher to be used in GCM mode to generate the MAC.
+ */
+ public GMac(final GCMBlockCipher cipher)
+ {
+ this(cipher, 128);
+ }
+
+ /**
+ * Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+ *
+ * @param macSizeBits
+ * the mac size to generate, in bits. Must be a multiple of 8 and >= 96 and <= 128.
+ * @param cipher
+ * the cipher to be used in GCM mode to generate the MAC.
+ */
+ public GMac(final GCMBlockCipher cipher, final int macSizeBits)
+ {
+ this.cipher = cipher;
+ this.macSizeBits = macSizeBits;
+ }
+
+ /**
+ * Initialises the GMAC - requires a {@link ParametersWithIV} providing a {@link KeyParameter}
+ * and a nonce.
+ */
+ public void init(final CipherParameters params) throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ final ParametersWithIV param = (ParametersWithIV)params;
+
+ final byte[] iv = param.getIV();
+ final KeyParameter keyParam = (KeyParameter)param.getParameters();
+
+ // GCM is always operated in encrypt mode to calculate MAC
+ cipher.init(true, new AEADParameters(keyParam, macSizeBits, iv));
+ } else
+ {
+ throw new IllegalArgumentException("GMAC requires ParametersWithIV");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName() + "-GMAC";
+ }
+
+ public int getMacSize()
+ {
+ return macSizeBits / 8;
+ }
+
+ public void update(byte in) throws IllegalStateException
+ {
+ cipher.processAADByte(in);
+ }
+
+ public void update(byte[] in, int inOff, int len) throws DataLengthException, IllegalStateException
+ {
+ cipher.processAADBytes(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws DataLengthException, IllegalStateException
+ {
+ try
+ {
+ return cipher.doFinal(out, outOff);
+ } catch (InvalidCipherTextException e)
+ {
+ // Impossible in encrypt mode
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/src/main/java/org/bouncycastle/crypto/macs/HMac.java
index 382d0e33..d4345d9b 100644
--- a/src/main/java/org/bouncycastle/crypto/macs/HMac.java
+++ b/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -8,6 +8,7 @@ import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Integers;
+import org.bouncycastle.util.Memoable;
/**
* HMAC implementation based on RFC2104
@@ -23,7 +24,9 @@ public class HMac
private Digest digest;
private int digestSize;
private int blockLength;
-
+ private Memoable ipadState;
+ private Memoable opadState;
+
private byte[] inputPad;
private byte[] outputBuf;
@@ -133,7 +136,19 @@ public class HMac
xorPad(inputPad, blockLength, IPAD);
xorPad(outputBuf, blockLength, OPAD);
+ if (digest instanceof Memoable)
+ {
+ opadState = ((Memoable)digest).copy();
+
+ ((Digest)opadState).update(outputBuf, 0, blockLength);
+ }
+
digest.update(inputPad, 0, inputPad.length);
+
+ if (digest instanceof Memoable)
+ {
+ ipadState = ((Memoable)digest).copy();
+ }
}
public int getMacSize()
@@ -160,7 +175,17 @@ public class HMac
int outOff)
{
digest.doFinal(outputBuf, blockLength);
- digest.update(outputBuf, 0, outputBuf.length);
+
+ if (opadState != null)
+ {
+ ((Memoable)digest).reset(opadState);
+ digest.update(outputBuf, blockLength, digest.getDigestSize());
+ }
+ else
+ {
+ digest.update(outputBuf, 0, outputBuf.length);
+ }
+
int len = digest.doFinal(out, outOff);
for (int i = blockLength; i < outputBuf.length; i++)
@@ -168,7 +193,14 @@ public class HMac
outputBuf[i] = 0;
}
- digest.update(inputPad, 0, inputPad.length);
+ if (ipadState != null)
+ {
+ ((Memoable)digest).reset(ipadState);
+ }
+ else
+ {
+ digest.update(inputPad, 0, inputPad.length);
+ }
return len;
}
diff --git a/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
index 600dd297..9a6e2e0c 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -1,378 +1,378 @@
-package org.bouncycastle.crypto.modes;
-
-import java.io.ByteArrayOutputStream;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.util.Arrays;
-
-/**
- * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
- * NIST Special Publication 800-38C.
- * <p>
- * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
- */
-public class CCMBlockCipher
- implements AEADBlockCipher
-{
- private BlockCipher cipher;
- private int blockSize;
- private boolean forEncryption;
- private byte[] nonce;
- private byte[] initialAssociatedText;
- private int macSize;
- private CipherParameters keyParam;
- private byte[] macBlock;
- private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
- private ByteArrayOutputStream data = new ByteArrayOutputStream();
-
- /**
- * Basic constructor.
- *
- * @param c the block cipher to be used.
- */
- public CCMBlockCipher(BlockCipher c)
- {
- 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.");
- }
- }
-
- /**
- * 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, CipherParameters params)
- throws IllegalArgumentException
- {
- this.forEncryption = forEncryption;
-
- if (params instanceof AEADParameters)
- {
- AEADParameters param = (AEADParameters)params;
-
- nonce = param.getNonce();
- initialAssociatedText = param.getAssociatedText();
- macSize = param.getMacSize() / 8;
- keyParam = param.getKey();
- }
- else if (params instanceof ParametersWithIV)
- {
- ParametersWithIV param = (ParametersWithIV)params;
-
- nonce = param.getIV();
- initialAssociatedText = null;
- macSize = macBlock.length / 2;
- keyParam = param.getParameters();
- }
- else
- {
- throw new IllegalArgumentException("invalid parameters passed to CCM");
- }
-
- if (nonce == null || nonce.length < 7 || nonce.length > 13)
- {
- throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
- }
- }
-
- public String getAlgorithmName()
- {
- return cipher.getAlgorithmName() + "/CCM";
- }
-
- public void processAADByte(byte in)
- {
- associatedText.write(in);
- }
-
- public void processAADBytes(byte[] in, int inOff, int len)
- {
- // TODO: Process AAD online
- associatedText.write(in, inOff, len);
- }
-
- public int processByte(byte in, byte[] out, int outOff)
- throws DataLengthException, IllegalStateException
- {
- data.write(in);
-
- return 0;
- }
-
- public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
- throws DataLengthException, IllegalStateException
- {
- data.write(in, inOff, inLen);
-
- return 0;
- }
-
- public int doFinal(byte[] out, int outOff)
- throws IllegalStateException, InvalidCipherTextException
- {
- byte[] text = data.toByteArray();
- byte[] enc = processPacket(text, 0, text.length);
-
- System.arraycopy(enc, 0, out, outOff, enc.length);
-
- reset();
-
- return enc.length;
- }
-
- public void reset()
- {
- cipher.reset();
- associatedText.reset();
- data.reset();
- }
-
- /**
- * 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;
- }
-
- public int getUpdateOutputSize(int len)
- {
- return 0;
- }
-
- public int getOutputSize(int len)
- {
- int totalData = len + data.size();
-
- if (forEncryption)
- {
- return totalData + macSize;
- }
-
- return totalData < macSize ? 0 : totalData - macSize;
- }
-
- public byte[] processPacket(byte[] in, int inOff, int inLen)
- throws IllegalStateException, InvalidCipherTextException
- {
- // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
- // Need to keep the CTR and CBC Mac parts around and reset
- if (keyParam == null)
- {
- throw new IllegalStateException("CCM cipher unitialized.");
- }
-
- int n = nonce.length;
- int q = 15 - n;
- if (q < 4)
- {
- int limitLen = 1 << (8 * q);
- if (inLen >= limitLen)
- {
- throw new IllegalStateException("CCM packet too large for choice of q.");
- }
- }
-
- byte[] iv = new byte[blockSize];
- iv[0] = (byte)((q - 1) & 0x7);
- System.arraycopy(nonce, 0, iv, 1, nonce.length);
-
- BlockCipher ctrCipher = new SICBlockCipher(cipher);
- ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
-
- int index = inOff;
- int outOff = 0;
- byte[] output;
-
- if (forEncryption)
- {
- output = new byte[inLen + macSize];
-
- calculateMac(in, inOff, inLen, macBlock);
-
- ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0
-
- while (index < inLen - blockSize) // S1...
- {
- ctrCipher.processBlock(in, index, output, outOff);
- outOff += blockSize;
- index += blockSize;
- }
-
- byte[] block = new byte[blockSize];
-
- System.arraycopy(in, index, block, 0, inLen - index);
-
- ctrCipher.processBlock(block, 0, block, 0);
-
- System.arraycopy(block, 0, output, outOff, inLen - index);
-
- outOff += inLen - index;
-
- System.arraycopy(macBlock, 0, output, outOff, output.length - outOff);
- }
- else
- {
- output = new byte[inLen - macSize];
-
- System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
-
- ctrCipher.processBlock(macBlock, 0, macBlock, 0);
-
- for (int i = macSize; i != macBlock.length; i++)
- {
- macBlock[i] = 0;
- }
-
- while (outOff < output.length - blockSize)
- {
- ctrCipher.processBlock(in, index, output, outOff);
- outOff += blockSize;
- index += blockSize;
- }
-
- byte[] block = new byte[blockSize];
-
- System.arraycopy(in, index, block, 0, output.length - outOff);
-
- ctrCipher.processBlock(block, 0, block, 0);
-
- System.arraycopy(block, 0, output, outOff, output.length - outOff);
-
- byte[] calculatedMacBlock = new byte[blockSize];
-
- calculateMac(output, 0, output.length, calculatedMacBlock);
-
- if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
- {
- throw new InvalidCipherTextException("mac check in CCM failed");
- }
- }
-
- return output;
- }
-
- private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
- {
- Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
-
- cMac.init(keyParam);
-
- //
- // 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)
- {
- b0[b0.length - count] = (byte)(q & 0xff);
- 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
- {
- cMac.update((byte)0xff);
- cMac.update((byte)0xfe);
- cMac.update((byte)(textLength >> 24));
- cMac.update((byte)(textLength >> 16));
- cMac.update((byte)(textLength >> 8));
- cMac.update((byte)textLength);
-
- extra = 6;
- }
-
- if (initialAssociatedText != null)
- {
- cMac.update(initialAssociatedText, 0, initialAssociatedText.length);
- }
- if (associatedText.size() > 0)
- {
- byte[] tmp = associatedText.toByteArray();
- cMac.update(tmp, 0, tmp.length);
- }
-
- extra = (extra + textLength) % 16;
- if (extra != 0)
- {
- for (int i = extra; i != 16; i++)
- {
- cMac.update((byte)0x00);
- }
- }
- }
-
- //
- // add the text
- //
- cMac.update(data, dataOff, dataLen);
-
- return cMac.doFinal(macBlock, 0);
- }
-
- private int getAssociatedTextLength()
- {
- return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length);
- }
-
- private boolean hasAssociatedText()
- {
- return getAssociatedTextLength() > 0;
- }
-}
+package org.bouncycastle.crypto.modes;
+
+import java.io.ByteArrayOutputStream;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+import org.bouncycastle.crypto.params.AEADParameters;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ * <p>
+ * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+ */
+public class CCMBlockCipher
+ implements AEADBlockCipher
+{
+ private BlockCipher cipher;
+ private int blockSize;
+ private boolean forEncryption;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
+ private int macSize;
+ private CipherParameters keyParam;
+ private byte[] macBlock;
+ private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
+ private ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public CCMBlockCipher(BlockCipher c)
+ {
+ 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.");
+ }
+ }
+
+ /**
+ * 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, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ initialAssociatedText = param.getAssociatedText();
+ macSize = param.getMacSize() / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ initialAssociatedText = null;
+ macSize = macBlock.length / 2;
+ keyParam = param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to CCM");
+ }
+
+ if (nonce == null || nonce.length < 7 || nonce.length > 13)
+ {
+ throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CCM";
+ }
+
+ public void processAADByte(byte in)
+ {
+ associatedText.write(in);
+ }
+
+ public void processAADBytes(byte[] in, int inOff, int len)
+ {
+ // TODO: Process AAD online
+ associatedText.write(in, inOff, len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in);
+
+ return 0;
+ }
+
+ public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in, inOff, inLen);
+
+ return 0;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ byte[] text = data.toByteArray();
+ byte[] enc = processPacket(text, 0, text.length);
+
+ System.arraycopy(enc, 0, out, outOff, enc.length);
+
+ reset();
+
+ return enc.length;
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ associatedText.reset();
+ data.reset();
+ }
+
+ /**
+ * 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;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return 0;
+ }
+
+ public int getOutputSize(int len)
+ {
+ int totalData = len + data.size();
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ public byte[] processPacket(byte[] in, int inOff, int inLen)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
+ // Need to keep the CTR and CBC Mac parts around and reset
+ if (keyParam == null)
+ {
+ throw new IllegalStateException("CCM cipher unitialized.");
+ }
+
+ int n = nonce.length;
+ int q = 15 - n;
+ if (q < 4)
+ {
+ int limitLen = 1 << (8 * q);
+ if (inLen >= limitLen)
+ {
+ throw new IllegalStateException("CCM packet too large for choice of q.");
+ }
+ }
+
+ byte[] iv = new byte[blockSize];
+ iv[0] = (byte)((q - 1) & 0x7);
+ System.arraycopy(nonce, 0, iv, 1, nonce.length);
+
+ BlockCipher ctrCipher = new SICBlockCipher(cipher);
+ ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+ int index = inOff;
+ int outOff = 0;
+ byte[] output;
+
+ if (forEncryption)
+ {
+ output = new byte[inLen + macSize];
+
+ calculateMac(in, inOff, inLen, macBlock);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0
+
+ while (index < inLen - blockSize) // S1...
+ {
+ ctrCipher.processBlock(in, index, output, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, inLen - index);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, output, outOff, inLen - index);
+
+ outOff += inLen - index;
+
+ System.arraycopy(macBlock, 0, output, outOff, output.length - outOff);
+ }
+ else
+ {
+ output = new byte[inLen - macSize];
+
+ System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0);
+
+ for (int i = macSize; i != macBlock.length; i++)
+ {
+ macBlock[i] = 0;
+ }
+
+ while (outOff < output.length - blockSize)
+ {
+ ctrCipher.processBlock(in, index, output, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, output.length - outOff);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, output, outOff, output.length - outOff);
+
+ byte[] calculatedMacBlock = new byte[blockSize];
+
+ calculateMac(output, 0, output.length, calculatedMacBlock);
+
+ if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
+ {
+ throw new InvalidCipherTextException("mac check in CCM failed");
+ }
+ }
+
+ return output;
+ }
+
+ private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ {
+ Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
+
+ cMac.init(keyParam);
+
+ //
+ // 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)
+ {
+ b0[b0.length - count] = (byte)(q & 0xff);
+ 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
+ {
+ cMac.update((byte)0xff);
+ cMac.update((byte)0xfe);
+ cMac.update((byte)(textLength >> 24));
+ cMac.update((byte)(textLength >> 16));
+ cMac.update((byte)(textLength >> 8));
+ cMac.update((byte)textLength);
+
+ extra = 6;
+ }
+
+ if (initialAssociatedText != null)
+ {
+ cMac.update(initialAssociatedText, 0, initialAssociatedText.length);
+ }
+ if (associatedText.size() > 0)
+ {
+ byte[] tmp = associatedText.toByteArray();
+ cMac.update(tmp, 0, tmp.length);
+ }
+
+ extra = (extra + textLength) % 16;
+ if (extra != 0)
+ {
+ for (int i = extra; i != 16; i++)
+ {
+ cMac.update((byte)0x00);
+ }
+ }
+ }
+
+ //
+ // add the text
+ //
+ cMac.update(data, dataOff, dataLen);
+
+ return cMac.doFinal(macBlock, 0);
+ }
+
+ private int getAssociatedTextLength()
+ {
+ return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length);
+ }
+
+ private boolean hasAssociatedText()
+ {
+ return getAssociatedTextLength() > 0;
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java b/src/main/java/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java
new file mode 100644
index 00000000..ba841b8e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+public class DSAParameterGenerationParameters
+{
+ public static final int DIGITAL_SIGNATURE_USAGE = 1;
+ public static final int KEY_ESTABLISHMENT_USAGE = 2;
+
+ private final int l;
+ private final int n;
+ private final int usageIndex;
+ private final int certainty;
+ private final SecureRandom random;
+
+ /**
+ * Construct without a usage index, this will do a random construction of G.
+ *
+ * @param L desired length of prime P in bits (the effective key size).
+ * @param N desired length of prime Q in bits.
+ * @param certainty certainty level for prime number generation.
+ * @param random the source of randomness to use.
+ */
+ public DSAParameterGenerationParameters(
+ int L,
+ int N,
+ int certainty,
+ SecureRandom random)
+ {
+ this(L, N, certainty, random, -1);
+ }
+
+ /**
+ * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G.
+ *
+ * @param L desired length of prime P in bits (the effective key size).
+ * @param N desired length of prime Q in bits.
+ * @param certainty certainty level for prime number generation.
+ * @param random the source of randomness to use.
+ * @param usageIndex a valid usage index.
+ */
+ public DSAParameterGenerationParameters(
+ int L,
+ int N,
+ int certainty,
+ SecureRandom random,
+ int usageIndex)
+ {
+ this.l = L;
+ this.n = N;
+ this.certainty = certainty;
+ this.usageIndex = usageIndex;
+ this.random = random;
+ }
+
+ public int getL()
+ {
+ return l;
+ }
+
+ public int getN()
+ {
+ return n;
+ }
+
+ public int getCertainty()
+ {
+ return certainty;
+ }
+
+ public SecureRandom getRandom()
+ {
+ return random;
+ }
+
+ public int getUsageIndex()
+ {
+ return usageIndex;
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java b/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
index 1cc4b93e..07d93d07 100644
--- a/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
+++ b/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
@@ -4,6 +4,7 @@ import org.bouncycastle.util.Arrays;
public class DSAValidationParameters
{
+ private int usageIndex;
private byte[] seed;
private int counter;
@@ -11,8 +12,17 @@ public class DSAValidationParameters
byte[] seed,
int counter)
{
+ this(seed, counter, -1);
+ }
+
+ public DSAValidationParameters(
+ byte[] seed,
+ int counter,
+ int usageIndex)
+ {
this.seed = seed;
this.counter = counter;
+ this.usageIndex = usageIndex;
}
public int getCounter()
@@ -25,6 +35,11 @@ public class DSAValidationParameters
return seed;
}
+ public int getUsageIndex()
+ {
+ return usageIndex;
+ }
+
public int hashCode()
{
return counter ^ Arrays.hashCode(seed);
diff --git a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
index 38527107..9f1d0427 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
@@ -43,6 +43,11 @@ public class BasicEntropySourceProvider
{
return _sr.generateSeed((bitsRequired + 7) / 8);
}
+
+ public int entropySize()
+ {
+ return bitsRequired;
+ }
};
}
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/DRBGProvider.java b/src/main/java/org/bouncycastle/crypto/prng/DRBGProvider.java
new file mode 100644
index 00000000..c39760c9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/prng/DRBGProvider.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.crypto.prng;
+
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+
+interface DRBGProvider
+{
+ SP80090DRBG get(EntropySource entropySource);
+}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java b/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
index 56a19711..53bc549d 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
@@ -2,7 +2,24 @@ package org.bouncycastle.crypto.prng;
public interface EntropySource
{
+ /**
+ * Return whether or not this entropy source is regarded as prediction resistant.
+ *
+ * @return true if it is, false otherwise.
+ */
boolean isPredictionResistant();
+ /**
+ * Return a byte array of entropy.
+ *
+ * @return entropy bytes.
+ */
byte[] getEntropy();
+
+ /**
+ * Return the number of bits of entropy this source can produce.
+ *
+ * @return size in bits of the return value of getEntropy.
+ */
+ int entropySize();
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/SP80090DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/SP80090DRBG.java
deleted file mode 100644
index 9fbd88f7..00000000
--- a/src/main/java/org/bouncycastle/crypto/prng/SP80090DRBG.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.bouncycastle.crypto.prng;
-
-public interface SP80090DRBG
-{
-
- int generate(byte[] output, byte[] additionalInput, boolean predictionResistant);
-
- void reseed(byte[] additionalInput);
-}
diff --git a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandom.java
index 0b54ac54..e1ec6c28 100644
--- a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandom.java
@@ -1,9 +1,8 @@
-package org.bouncycastle.crypto.random;
+package org.bouncycastle.crypto.prng;
import java.security.SecureRandom;
-import org.bouncycastle.crypto.prng.EntropySource;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
public class SP800SecureRandom
extends SecureRandom
@@ -55,7 +54,12 @@ public class SP800SecureRandom
drbg = drbgProvider.get(entropySource);
}
- drbg.generate(bytes, null, predictionResistant);
+ // check if a reseed is required...
+ if (drbg.generate(bytes, null, predictionResistant) < 0)
+ {
+ drbg.reseed(entropySource.getEntropy());
+ drbg.generate(bytes, null, predictionResistant);
+ }
}
}
diff --git a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
index 10bd3505..66f05c5f 100644
--- a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
@@ -1,18 +1,15 @@
-package org.bouncycastle.crypto.random;
+package org.bouncycastle.crypto.prng;
import java.security.SecureRandom;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.prng.BasicEntropySourceProvider;
-import org.bouncycastle.crypto.prng.CTRSP800DRBG;
-import org.bouncycastle.crypto.prng.DualECSP800DRBG;
-import org.bouncycastle.crypto.prng.EntropySource;
-import org.bouncycastle.crypto.prng.EntropySourceProvider;
-import org.bouncycastle.crypto.prng.HMacSP800DRBG;
-import org.bouncycastle.crypto.prng.HashSP800DRBG;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
+import org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.DualECSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
/**
* Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG).
@@ -31,7 +28,7 @@ public class SP800SecureRandomBuilder
* predictionResistant set to false.
* <p>
* Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
- * the passed in SecureRandom does.
+ * the default SecureRandom does for its generateSeed() call.
* </p>
*/
public SP800SecureRandomBuilder()
@@ -44,7 +41,7 @@ public class SP800SecureRandomBuilder
* for prediction resistance.
* <p>
* Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
- * the passed in SecureRandom does.
+ * the passed in SecureRandom does for its generateSeed() call.
* </p>
* @param entropySource
* @param predictionResistant
@@ -177,7 +174,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new HashSP800DRBG(digest, entropySource, nonce, personalizationString, securityStrength);
+ return new HashSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce);
}
}
@@ -199,7 +196,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new DualECSP800DRBG(digest, entropySource, nonce, personalizationString, securityStrength);
+ return new DualECSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce);
}
}
@@ -221,7 +218,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new HMacSP800DRBG(hMac, entropySource, nonce, personalizationString, securityStrength);
+ return new HMacSP800DRBG(hMac, securityStrength, entropySource, personalizationString, nonce);
}
}
@@ -246,7 +243,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new CTRSP800DRBG(blockCipher, keySizeInBits, entropySource, nonce, personalizationString, securityStrength);
+ return new CTRSP800DRBG(blockCipher, keySizeInBits, securityStrength, entropySource, personalizationString, nonce);
}
}
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/VMPCRandomGenerator.java b/src/main/java/org/bouncycastle/crypto/prng/VMPCRandomGenerator.java
index 9f9ff7b2..b882b796 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/VMPCRandomGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/VMPCRandomGenerator.java
@@ -124,5 +124,4 @@ public class VMPCRandomGenerator implements RandomGenerator
}
}
}
-
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/CTRSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
index 8311e079..84fe4a40 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/CTRSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
@@ -1,14 +1,23 @@
-package org.bouncycastle.crypto.prng;
+package org.bouncycastle.crypto.prng.drbg;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
+/**
+ * A SP800-90A CTR DRBG.
+ */
public class CTRSP800DRBG
implements SP80090DRBG
{
- private EntropySource _entropySource;
+ private static final long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static final long AES_RESEED_MAX = 1L << (48 - 1);
+ private static final int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static final int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private EntropySource _entropySource;
private BlockCipher _engine;
private int _keySizeInBits;
private int _seedLength;
@@ -16,62 +25,64 @@ public class CTRSP800DRBG
// internal state
private byte[] _Key;
private byte[] _V;
- private int _reseedCounter = 0;
-
- public CTRSP800DRBG(BlockCipher engine, int keySizeInBits, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
+ private long _reseedCounter = 0;
+ private boolean _isTDEA = false;
+
+ /**
+ * Construct a SP800-90A CTR DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param engine underlying block cipher to use to support DRBG
+ * @param keySizeInBits size of the key to use with the block cipher.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public CTRSP800DRBG(BlockCipher engine, int keySizeInBits, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
-
_entropySource = entropySource;
_engine = engine;
_keySizeInBits = keySizeInBits;
_seedLength = keySizeInBits + engine.getBlockSize() * 8;
+ _isTDEA = isTDEA(engine);
- int entropyLengthInBytes = securityStrength;
-
if (securityStrength > 256)
{
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
+ }
+
+ if (getMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by block cipher and key size");
}
-
- byte[] entropy = entropySource.getEntropy(); // Get_entropy_input
- System.out.println("Constructor Entropy: " + new String(Hex.encode(entropy)));
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
- CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalisationString);
-
- System.err.println("Constructor V : " + new String(Hex.encode(_V)));
- System.err.println("Constructor Key: " + new String(Hex.encode(_Key)));
+ byte[] entropy = entropySource.getEntropy(); // Get_entropy_input
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
}
private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce,
byte[] personalisationString)
{
- if (personalisationString == null)
- {
- personalisationString = new byte[0];
- }
-
byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString);
-
- System.out.println("Constructor SeedMaterial: " + new String(Hex.encode(seedMaterial)));
-
byte[] seed = Block_Cipher_df(seedMaterial, _seedLength);
- System.out.println("Constructor Seed: " + new String(Hex.encode(seed)));
-
int outlen = _engine.getBlockSize();
_Key = new byte[(_keySizeInBits + 7) / 8];
_V = new byte[outlen];
+ // _Key & _V are modified by this call
CTR_DRBG_Update(seed, _Key, _V);
- // _Key & _V are modified by this call
- System.out.println("Key: " + new String(Hex.encode(_Key)));
- System.out.println("V : " + new String(Hex.encode(_V)));
+
_reseedCounter = 1;
}
@@ -83,7 +94,7 @@ public class CTRSP800DRBG
int i=0;
int outLen = _engine.getBlockSize();
- _engine.init(true, new KeyParameter(key));
+ _engine.init(true, new KeyParameter(expandKey(key)));
while (i*outLen < seed.length)
{
addOneTo(v);
@@ -95,18 +106,22 @@ public class CTRSP800DRBG
System.arraycopy(outputBlock, 0, temp, i * outLen, bytesToCopy);
++i;
}
- System.err.println("seed: " + new String(Hex.encode(seed)));
- System.err.println("temp: " + new String(Hex.encode(temp)));
+
XOR(temp, seed, temp, 0);
- System.err.println("temp: " + new String(Hex.encode(temp)));
+
System.arraycopy(temp, 0, key, 0, key.length);
System.arraycopy(temp, key.length, v, 0, v.length);
}
private void CTR_DRBG_Reseed_algorithm(EntropySource entropy, byte[] additionalInput)
{
-
-
+ byte[] seedMaterial = Arrays.concatenate(entropy.getEntropy(), additionalInput);
+
+ seedMaterial = Block_Cipher_df(seedMaterial, _seedLength);
+
+ CTR_DRBG_Update(seedMaterial, _Key, _V);
+
+ _reseedCounter = 1;
}
private void XOR(byte[] out, byte[] a, byte[] b, int bOff)
@@ -131,16 +146,6 @@ public class CTRSP800DRBG
// -- Internal state migration ---
private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
-
- private byte[] getBytes(byte[] input)
- {
- byte[] K = new byte[_keySizeInBits / 8];
- System.arraycopy(K_BITS, 0, K, 0, K.length);
- _engine.init(true, new KeyParameter(K));
- byte[] out = new byte[_engine.getBlockSize()];
- _engine.processBlock(input, 0, out, 0);
- return out;
- }
// 1. If (number_of_bits_to_return > max_number_of_bits), then return an
// ERROR_FLAG.
@@ -216,7 +221,7 @@ public class CTRSP800DRBG
System.arraycopy(inputString, 0, S, 8, L);
S[8 + L] = (byte)0x80;
// S already padded with zeros
- System.err.println("S :" + new String(Hex.encode(S)));
+
byte[] temp = new byte[_keySizeInBits / 8 + outLen];
byte[] bccOut = new byte[outLen];
@@ -246,7 +251,7 @@ public class CTRSP800DRBG
temp = new byte[bitLength / 2];
i = 0;
- _engine.init(true, new KeyParameter(K));
+ _engine.init(true, new KeyParameter(expandKey(K)));
while (i * outLen < temp.length)
{
@@ -263,7 +268,6 @@ public class CTRSP800DRBG
return temp;
}
-
/*
* 1. chaining_value = 0^outlen
* . Comment: Set the first chaining value to outlen zeros.
@@ -284,7 +288,7 @@ public class CTRSP800DRBG
byte[] inputBlock = new byte[outlen];
- _engine.init(true, new KeyParameter(k));
+ _engine.init(true, new KeyParameter(expandKey(k)));
_engine.processBlock(iV, 0, chainingValue, 0);
@@ -305,11 +309,46 @@ public class CTRSP800DRBG
buf[offSet + 3] = ((byte)(value));
}
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
{
+ if (_isTDEA)
+ {
+ if (_reseedCounter > TDEA_RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (Utils.isTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST);
+ }
+ }
+ else
+ {
+ if (_reseedCounter > AES_RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (Utils.isTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST);
+ }
+ }
+
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(_entropySource, additionalInput);
+ additionalInput = null;
}
if (additionalInput != null)
@@ -324,7 +363,7 @@ public class CTRSP800DRBG
byte[] out = new byte[_V.length];
- _engine.init(true, new KeyParameter(_Key));
+ _engine.init(true, new KeyParameter(expandKey(_Key)));
for (int i = 0; i < output.length / out.length; i++)
{
@@ -339,7 +378,6 @@ public class CTRSP800DRBG
System.arraycopy(out, 0, output, i * out.length, bytesToCopy);
}
-
CTR_DRBG_Update(additionalInput, _Key, _V);
_reseedCounter++;
@@ -347,8 +385,84 @@ public class CTRSP800DRBG
return output.length * 8;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
CTR_DRBG_Reseed_algorithm(_entropySource, additionalInput);
}
+
+ private boolean isTDEA(BlockCipher cipher)
+ {
+ return cipher.getAlgorithmName().equals("DESede") || cipher.getAlgorithmName().equals("TDEA");
+ }
+
+ private int getMaxSecurityStrength(BlockCipher cipher, int keySizeInBits)
+ {
+ if (isTDEA(cipher) && keySizeInBits == 168)
+ {
+ return 112;
+ }
+ if (cipher.getAlgorithmName().equals("AES"))
+ {
+ return keySizeInBits;
+ }
+
+ return -1;
+ }
+
+ byte[] expandKey(byte[] key)
+ {
+ if (_isTDEA)
+ {
+ // expand key to 192 bits.
+ byte[] tmp = new byte[24];
+
+ padKey(key, 0, tmp, 0);
+ padKey(key, 7, tmp, 8);
+ padKey(key, 14, tmp, 16);
+
+ return tmp;
+ }
+ else
+ {
+ return key;
+ }
+ }
+
+ /**
+ * Pad out a key for TDEA, setting odd parity for each byte.
+ *
+ * @param keyMaster
+ * @param keyOff
+ * @param tmp
+ * @param tmpOff
+ */
+ private void padKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
+ {
+ tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
+ tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >>> 1));
+ tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >>> 2));
+ tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >>> 3));
+ tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >>> 4));
+ tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >>> 5));
+ tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >>> 6));
+ tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
+
+ for (int i = tmpOff; i <= tmpOff + 7; i++)
+ {
+ int b = tmp[i];
+ tmp[i] = (byte)((b & 0xfe) |
+ ((((b >> 1) ^
+ (b >> 2) ^
+ (b >> 3) ^
+ (b >> 4) ^
+ (b >> 5) ^
+ (b >> 6) ^
+ (b >> 7)) ^ 0x01) & 0x01));
+ }
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/DualECSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
index caeac7a0..3cee39cb 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/DualECSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
@@ -1,15 +1,19 @@
-package org.bouncycastle.crypto.prng;
+package org.bouncycastle.crypto.prng.drbg;
import java.math.BigInteger;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+/**
+ * A SP800-90A Dual EC DRBG.
+ */
public class DualECSP800DRBG
implements SP80090DRBG
{
@@ -31,10 +35,13 @@ public class DualECSP800DRBG
private static final BigInteger p521_Qx = new BigInteger("1b9fa3e518d683c6b65763694ac8efbaec6fab44f2276171a42726507dd08add4c3b3f4c1ebc5b1222ddba077f722943b24c3edfa0f85fe24d0c8c01591f0be6f63", 16);
private static final BigInteger p521_Qy = new BigInteger("1f3bdba585295d9a1110d1df1f9430ef8442c5018976ff3437ef91b81dc0b8132c8d5c39c32d0e004a3092b7d327c0e7a4d26d2c7b69b58f9066652911e457779de", 16);
- private final static int RESEED_MAX = 100000;
+ private static final long RESEED_MAX = 1L << (32 - 1);
+ private static final int MAX_ADDITIONAL_INPUT = 1 << (13 - 1);
+ private static final int MAX_ENTROPY_LENGTH = 1 << (13 - 1);
+ private static final int MAX_PERSONALIZATION_STRING = 1 << (13 -1);
private Digest _digest;
- private int _reseedCounter;
+ private long _reseedCounter;
private EntropySource _entropySource;
private int _securityStrength;
private int _seedlen;
@@ -43,28 +50,44 @@ public class DualECSP800DRBG
private ECPoint _P;
private ECPoint _Q;
private byte[] _s;
- private int _sLength;
-
- public DualECSP800DRBG(Digest digest, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
+ private int _sLength;
+
+ /**
+ * Construct a SP800-90A Dual EC DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param digest source digest to use with the DRB stream.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public DualECSP800DRBG(Digest digest, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
- if (securityStrength > digest.getDigestSize() * 8) // TODO: this may, or may not be correct, but it's good enough for now
- {
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
- }
-
- // TODO: validate digest choice
_digest = digest;
_entropySource = entropySource;
_securityStrength = securityStrength;
- // TODO: validate entropy length
+ if (Utils.isTooLarge(personalizationString, MAX_PERSONALIZATION_STRING / 8))
+ {
+ throw new IllegalArgumentException("Personalization string too large");
+ }
+
+ if (entropySource.entropySize() < securityStrength || entropySource.entropySize() > MAX_ENTROPY_LENGTH)
+ {
+ throw new IllegalArgumentException("EntropySource must provide between " + securityStrength + " and " + MAX_ENTROPY_LENGTH + " bits");
+ }
+
byte[] entropy = entropySource.getEntropy();
- byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString);
+ byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString);
if (securityStrength <= 128)
{
+ if (Utils.getMaxSecurityStrength(digest) < 128)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 256;
_outlen = 240 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-256").getCurve();
@@ -73,6 +96,10 @@ public class DualECSP800DRBG
}
else if (securityStrength <= 192)
{
+ if (Utils.getMaxSecurityStrength(digest) < 192)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 384;
_outlen = 368 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-384").getCurve();
@@ -81,6 +108,10 @@ public class DualECSP800DRBG
}
else if (securityStrength <= 256)
{
+ if (Utils.getMaxSecurityStrength(digest) < 256)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 521;
_outlen = 504 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-521").getCurve();
@@ -92,19 +123,37 @@ public class DualECSP800DRBG
throw new IllegalArgumentException("security strength cannot be greater than 256 bits");
}
- _s = hash_df(seedMaterial, _seedlen);
+ _s = Utils.hash_df(_digest, seedMaterial, _seedlen);
_sLength = _s.length;
- //System.err.println(new String(Hex.encode(_s)));
_reseedCounter = 0;
-
}
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
{
int numberOfBits = output.length*8;
-
- if (predictionResistant || _reseedCounter > RESEED_MAX)
+ int m = output.length / _outlen;
+
+ if (Utils.isTooLarge(additionalInput, MAX_ADDITIONAL_INPUT / 8))
+ {
+ throw new IllegalArgumentException("Additional input too large");
+ }
+
+ if (_reseedCounter + m > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
{
reseed(additionalInput);
additionalInput = null;
@@ -113,11 +162,9 @@ public class DualECSP800DRBG
if (additionalInput != null)
{
// Note: we ignore the use of pad8 on the additional input as we mandate byte arrays for it.
- additionalInput = hash_df(additionalInput, _seedlen);
+ additionalInput = Utils.hash_df(_digest, additionalInput, _seedlen);
}
- int m = output.length / _outlen;
-
for (int i = 0; i < m; i++)
{
BigInteger t = new BigInteger(1, xor(_s, additionalInput));
@@ -139,6 +186,8 @@ public class DualECSP800DRBG
//System.err.println("R: " + new String(Hex.encode(r)));
additionalInput = null;
+
+ _reseedCounter++;
}
if (m * _outlen < output.length)
@@ -155,84 +204,29 @@ public class DualECSP800DRBG
// Need to preserve length of S as unsigned int.
_s = BigIntegers.asUnsignedByteArray(_sLength, _P.multiply(new BigInteger(1, _s)).getX().toBigInteger());
- _reseedCounter++;
-
return numberOfBits;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
- if (additionalInput == null)
+ if (Utils.isTooLarge(additionalInput, MAX_ADDITIONAL_INPUT / 8))
{
- additionalInput = new byte[0];
+ throw new IllegalArgumentException("Additional input string too large");
}
byte[] entropy = _entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(pad8(_s, _seedlen), entropy, additionalInput);
- _s = hash_df(seedMaterial, _seedlen);
+ _s = Utils.hash_df(_digest, seedMaterial, _seedlen);
_reseedCounter = 0;
}
- // 1. temp = the Null string.
- // 2. .
- // 3. counter = an 8-bit binary value representing the integer "1".
- // 4. For i = 1 to len do
- // Comment : In step 4.1, no_of_bits_to_return
- // is used as a 32-bit string.
- // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
- // input_string).
- // 4.2 counter = counter + 1.
- // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
- // 6. Return SUCCESS and requested_bits.
- private byte[] hash_df(byte[] seedMaterial, int seedLength)
- {
- byte[] temp = new byte[(seedLength + 7) / 8];
-
- int len = temp.length / _digest.getDigestSize();
- int counter = 1;
-
- byte[] dig = new byte[_digest.getDigestSize()];
-
- for (int i = 0; i <= len; i++)
- {
- _digest.update((byte)counter);
-
- _digest.update((byte)(seedLength >> 24));
- _digest.update((byte)(seedLength >> 16));
- _digest.update((byte)(seedLength >> 8));
- _digest.update((byte)seedLength);
-
- _digest.update(seedMaterial, 0, seedMaterial.length);
-
- _digest.doFinal(dig, 0);
-
- int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
- ? dig.length
- : (temp.length - i * dig.length);
- System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
-
- counter++;
- }
-
- // do a left shift to get rid of excess bits.
- if (seedLength % 8 != 0)
- {
- int shift = 8 - (seedLength % 8);
- int carry = 0;
-
- for (int i = 0; i != temp.length; i++)
- {
- int b = temp[i] & 0xff;
- temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
- carry = b;
- }
- }
-
- return temp;
- }
-
private byte[] xor(byte[] a, byte[] b)
{
if (b == null)
diff --git a/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
index dd22f4c6..3ddeaac6 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
@@ -1,29 +1,53 @@
-package org.bouncycastle.crypto.prng;
+package org.bouncycastle.crypto.prng.drbg;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.util.Arrays;
+/**
+ * A SP800-90A HMAC DRBG.
+ */
public class HMacSP800DRBG
implements SP80090DRBG
{
+ private final static long RESEED_MAX = 1L << (48 - 1);
+ private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
private byte[] _K;
private byte[] _V;
- private int _reseedCounter;
+ private long _reseedCounter;
private EntropySource _entropySource;
private Mac _hMac;
- public HMacSP800DRBG(Mac hMac, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param hMac Hash MAC to base the DRBG on.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HMacSP800DRBG(Mac hMac, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
- // TODO: validate security strength
+ if (securityStrength > Utils.getMaxSecurityStrength(hMac))
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
+ }
+
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
_entropySource = entropySource;
_hMac = hMac;
- // TODO: validate entropy length
byte[] entropy = entropySource.getEntropy();
- byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString);
+ byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString);
_K = new byte[hMac.getMacSize()];
_V = new byte[_K.length];
@@ -63,12 +87,29 @@ public class HMacSP800DRBG
_hMac.doFinal(_V, 0);
}
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
{
- // TODO: check reseed counter
-
int numberOfBits = output.length * 8;
+ if (numberOfBits > MAX_BITS_REQUEST)
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
+ }
+
+ if (_reseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
if (predictionResistant)
{
reseed(additionalInput);
@@ -113,6 +154,11 @@ public class HMacSP800DRBG
return numberOfBits;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
byte[] entropy = _entropySource.getEntropy();
diff --git a/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
index c52dd917..4ed57163 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
@@ -1,305 +1,269 @@
-package org.bouncycastle.crypto.prng;
-
-import java.util.Hashtable;
-
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.Integers;
-
-public class HashSP800DRBG implements SP80090DRBG
-{
- private final static byte[] ONE = { 0x01 };
- private final static int RESEED_MAX = 100000;
- private final static Hashtable seedlens = new Hashtable();
-
- static
- {
- seedlens.put("SHA-1", Integers.valueOf(440));
- seedlens.put("SHA-224", Integers.valueOf(440));
- seedlens.put("SHA-256", Integers.valueOf(440));
- seedlens.put("SHA-512/256", Integers.valueOf(440));
- seedlens.put("SHA-512/224", Integers.valueOf(440));
- seedlens.put("SHA-384", Integers.valueOf(888));
- seedlens.put("SHA-512", Integers.valueOf(888));
- }
-
- private Digest _digest;
- private byte[] _V;
- private byte[] _C;
- private int _reseedCounter;
- private EntropySource _entropySource;
- private int _securityStrength;
- private int _seedLength;
-
- public HashSP800DRBG(Digest digest, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
- {
- if (securityStrength > digest.getDigestSize() * 8) // TODO: this may, or may not be correct, but it's good enough for now
- {
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
- }
-
- _digest = digest;
- _entropySource = entropySource;
- _securityStrength = securityStrength;
- _seedLength = ((Integer)seedlens.get(digest.getAlgorithmName())).intValue();
-
- // 1. seed_material = entropy_input || nonce || personalization_string.
- // 2. seed = Hash_df (seed_material, seedlen).
- // 3. V = seed.
- // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
- // of zeros.
- // 5. reseed_counter = 1.
- // 6. Return V, C, and reseed_counter as the initial_working_state
-
- byte[] entropy = entropySource.getEntropy();
- byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString);
- byte[] seed = hash_df(seedMaterial, _seedLength);
-
- _V = seed;
- byte[] subV = new byte[_V.length + 1];
- System.arraycopy(_V, 0, subV, 1, _V.length);
- _C = hash_df(subV, _seedLength);
- _reseedCounter = 1;
-
-// System.out.println("Constructor V: "+ new String(Hex.encode(_V)));
-// System.out.println("Constructor C: "+ new String(Hex.encode(_C)));
-
- }
-
- // 1. If reseed_counter > reseed_interval, then return an indication that a
- // reseed is required.
- // 2. If (additional_input != Null), then do
- // 2.1 w = Hash (0x02 || V || additional_input).
- // 2.2 V = (V + w) mod 2^seedlen
- // .
- // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
- // 4. H = Hash (0x03 || V).
- // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
- // .
- // 6. reseed_counter = reseed_counter + 1.
- // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
- // reseed_counter for the new_working_state.
- public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
- {
- int numberOfBits = output.length*8;
-
- if (predictionResistant || _reseedCounter > RESEED_MAX)
- {
- reseed(additionalInput);
- additionalInput = null;
- }
-
- // 2.
- if (additionalInput != null)
- {
- byte[] newInput = new byte[1 + _V.length + additionalInput.length];
- newInput[0] = 0x02;
- System.arraycopy(_V, 0, newInput, 1, _V.length);
- // TODO: inOff / inLength
- System.arraycopy(additionalInput, 0, newInput, 1 + _V.length, additionalInput.length);
- byte[] w = hash(newInput);
-
- addTo(_V, w);
- }
-
- // 3.
- byte[] rv = hashgen(_V, numberOfBits);
-
- // 4.
- byte[] subH = new byte[_V.length + 1];
- System.arraycopy(_V, 0, subH, 1, _V.length);
- subH[0] = 0x03;
-
- byte[] H = hash(subH);
-
- // 5.
- addTo(_V, H);
- addTo(_V, _C);
- byte[] c = new byte[4];
- c[0] = (byte)(_reseedCounter >> 24);
- c[1] = (byte)(_reseedCounter >> 16);
- c[2] = (byte)(_reseedCounter >> 8);
- c[3] = (byte)_reseedCounter;
-
- addTo(_V, c);
- _reseedCounter++;
-
- System.arraycopy(rv, 0, output, 0, output.length);
-// System.out.println("Generate V: "+ new String(Hex.encode(_V)));
-// System.out.println("Generate C: "+ new String(Hex.encode(_C)));
-
- return numberOfBits;
- }
-
- // this will always add the shorter length byte array mathematically to the
- // longer length byte array.
- // be careful....
- private void addTo(byte[] longer, byte[] shorter)
- {
- int carry = 0;
- for (int i=1;i <= shorter.length; i++) // warning
- {
- int res = (longer[longer.length-i] & 0xff) + (shorter[shorter.length-i] & 0xff) + carry;
- carry = (res > 0xff) ? 1 : 0;
- longer[longer.length-i] = (byte)res;
- }
-
- for (int i=shorter.length+1;i <= longer.length; i++) // warning
- {
- int res = (longer[longer.length-i] & 0xff) + carry;
- carry = (res > 0xff) ? 1 : 0;
- longer[longer.length-i] = (byte)res;
- }
- }
-
- // 1. seed_material = 0x01 || V || entropy_input || additional_input.
- //
- // 2. seed = Hash_df (seed_material, seedlen).
- //
- // 3. V = seed.
- //
- // 4. C = Hash_df ((0x00 || V), seedlen).
- //
- // 5. reseed_counter = 1.
- //
- // 6. Return V, C, and reseed_counter for the new_working_state.
- //
- // Comment: Precede with a byte of all zeros.
- public void reseed(byte[] additionalInput)
- {
- if (additionalInput == null)
- {
- additionalInput = new byte[0];
- }
-
- byte[] entropy = _entropySource.getEntropy();
-
-// System.out.println("Reseed Entropy: "+ new String(Hex.encode(entropy)));
-
- byte[] seedMaterial = Arrays.concatenate(ONE, _V, entropy, additionalInput);
-
-// System.out.println("Reseed SeedMaterial: "+ new String(Hex.encode(seedMaterial)));
-
- byte[] seed = hash_df(seedMaterial, _seedLength);
-
-// System.out.println("Reseed Seed: "+ new String(Hex.encode(seed)));
-
- _V = seed;
- byte[] subV = new byte[_V.length + 1];
- subV[0] = 0x00;
- System.arraycopy(_V, 0, subV, 1, _V.length);
- _C = hash_df(subV, _seedLength);
- _reseedCounter = 1;
-
-// System.out.println("Reseed V: "+ new String(Hex.encode(_V)));
-// System.out.println("Reseed C: "+ new String(Hex.encode(_C)));
- }
-
-
- // ---- Internal manipulation ---
- // ---- Migrating from the external HashDF class --
-
-
- // 1. temp = the Null string.
- // 2. .
- // 3. counter = an 8-bit binary value representing the integer "1".
- // 4. For i = 1 to len do
- // Comment : In step 4.1, no_of_bits_to_return
- // is used as a 32-bit string.
- // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
- // input_string).
- // 4.2 counter = counter + 1.
- // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
- // 6. Return SUCCESS and requested_bits.
- private byte[] hash_df(byte[] seedMaterial, int seedLength)
- {
- byte[] temp = new byte[seedLength / 8];
-
- int len = temp.length / _digest.getDigestSize();
- int counter = 1;
-
- byte[] dig = new byte[_digest.getDigestSize()];
-
- for (int i = 0; i <= len; i++)
- {
- _digest.update((byte)counter);
-
- _digest.update((byte)(seedLength >> 24));
- _digest.update((byte)(seedLength >> 16));
- _digest.update((byte)(seedLength >> 8));
- _digest.update((byte)seedLength);
-
- _digest.update(seedMaterial, 0, seedMaterial.length);
-
- _digest.doFinal(dig, 0);
-
- int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
- ? dig.length
- : (temp.length - i * dig.length);
- System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
-
- counter++;
- }
-
- // do a left shift to get rid of excess bits.
- if (seedLength % 8 != 0)
- {
- int shift = 8 - (seedLength % 8);
- int carry = 0;
-
- for (int i = 0; i != temp.length; i++)
- {
- int b = temp[i] & 0xff;
- temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
- carry = b;
- }
- }
-
- return temp;
- }
-
- private byte[] hash(byte[] input)
- {
- _digest.update(input, 0, input.length);
- byte[] hash = new byte[_digest.getDigestSize()];
- _digest.doFinal(hash, 0);
- return hash;
- }
-
- // 1. m = [requested_number_of_bits / outlen]
- // 2. data = V.
- // 3. W = the Null string.
- // 4. For i = 1 to m
- // 4.1 wi = Hash (data).
- // 4.2 W = W || wi.
- // 4.3 data = (data + 1) mod 2^seedlen
- // .
- // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
- private byte[] hashgen(byte[] input, int lengthInBits)
- {
- int digestSize = _digest.getDigestSize();
- int m = (lengthInBits / 8) / digestSize;
-
- byte[] data = new byte[input.length];
- System.arraycopy(input, 0, data, 0, input.length);
-
- byte[] W = new byte[lengthInBits / 8];
-
- byte[] dig;
- for (int i = 0; i <= m; i++)
- {
- dig = hash(data);
-
- int bytesToCopy = ((W.length - i * dig.length) > dig.length)
- ? dig.length
- : (W.length - i * dig.length);
- System.arraycopy(dig, 0, W, i * dig.length, bytesToCopy);
-
- addTo(data, ONE);
- }
-
- return W;
- }
-}
+package org.bouncycastle.crypto.prng.drbg;
+
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.prng.EntropySource;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Integers;
+
+/**
+ * A SP800-90A Hash DRBG.
+ */
+public class HashSP800DRBG
+ implements SP80090DRBG
+{
+ private final static byte[] ONE = { 0x01 };
+
+ private final static long RESEED_MAX = 1L << (48 - 1);
+ private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private final static Hashtable seedlens = new Hashtable();
+
+ static
+ {
+ seedlens.put("SHA-1", Integers.valueOf(440));
+ seedlens.put("SHA-224", Integers.valueOf(440));
+ seedlens.put("SHA-256", Integers.valueOf(440));
+ seedlens.put("SHA-512/256", Integers.valueOf(440));
+ seedlens.put("SHA-512/224", Integers.valueOf(440));
+ seedlens.put("SHA-384", Integers.valueOf(888));
+ seedlens.put("SHA-512", Integers.valueOf(888));
+ }
+
+ private Digest _digest;
+ private byte[] _V;
+ private byte[] _C;
+ private long _reseedCounter;
+ private EntropySource _entropySource;
+ private int _securityStrength;
+ private int _seedLength;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param digest source digest to use for DRB stream.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HashSP800DRBG(Digest digest, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > Utils.getMaxSecurityStrength(digest))
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
+ }
+
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
+
+ _digest = digest;
+ _entropySource = entropySource;
+ _securityStrength = securityStrength;
+ _seedLength = ((Integer)seedlens.get(digest.getAlgorithmName())).intValue();
+
+ // 1. seed_material = entropy_input || nonce || personalization_string.
+ // 2. seed = Hash_df (seed_material, seedlen).
+ // 3. V = seed.
+ // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
+ // of zeros.
+ // 5. reseed_counter = 1.
+ // 6. Return V, C, and reseed_counter as the initial_working_state
+
+ byte[] entropy = entropySource.getEntropy();
+ byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString);
+ byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
+
+ _V = seed;
+ byte[] subV = new byte[_V.length + 1];
+ System.arraycopy(_V, 0, subV, 1, _V.length);
+ _C = Utils.hash_df(_digest, subV, _seedLength);
+
+ _reseedCounter = 1;
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
+ {
+ // 1. If reseed_counter > reseed_interval, then return an indication that a
+ // reseed is required.
+ // 2. If (additional_input != Null), then do
+ // 2.1 w = Hash (0x02 || V || additional_input).
+ // 2.2 V = (V + w) mod 2^seedlen
+ // .
+ // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
+ // 4. H = Hash (0x03 || V).
+ // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
+ // .
+ // 6. reseed_counter = reseed_counter + 1.
+ // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
+ // reseed_counter for the new_working_state.
+ int numberOfBits = output.length*8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
+ }
+
+ if (_reseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
+ {
+ reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ byte[] newInput = new byte[1 + _V.length + additionalInput.length];
+ newInput[0] = 0x02;
+ System.arraycopy(_V, 0, newInput, 1, _V.length);
+ // TODO: inOff / inLength
+ System.arraycopy(additionalInput, 0, newInput, 1 + _V.length, additionalInput.length);
+ byte[] w = hash(newInput);
+
+ addTo(_V, w);
+ }
+
+ // 3.
+ byte[] rv = hashgen(_V, numberOfBits);
+
+ // 4.
+ byte[] subH = new byte[_V.length + 1];
+ System.arraycopy(_V, 0, subH, 1, _V.length);
+ subH[0] = 0x03;
+
+ byte[] H = hash(subH);
+
+ // 5.
+ addTo(_V, H);
+ addTo(_V, _C);
+ byte[] c = new byte[4];
+ c[0] = (byte)(_reseedCounter >> 24);
+ c[1] = (byte)(_reseedCounter >> 16);
+ c[2] = (byte)(_reseedCounter >> 8);
+ c[3] = (byte)_reseedCounter;
+
+ addTo(_V, c);
+
+ _reseedCounter++;
+
+ System.arraycopy(rv, 0, output, 0, output.length);
+
+ return numberOfBits;
+ }
+
+ // this will always add the shorter length byte array mathematically to the
+ // longer length byte array.
+ // be careful....
+ private void addTo(byte[] longer, byte[] shorter)
+ {
+ int carry = 0;
+ for (int i=1;i <= shorter.length; i++) // warning
+ {
+ int res = (longer[longer.length-i] & 0xff) + (shorter[shorter.length-i] & 0xff) + carry;
+ carry = (res > 0xff) ? 1 : 0;
+ longer[longer.length-i] = (byte)res;
+ }
+
+ for (int i=shorter.length+1;i <= longer.length; i++) // warning
+ {
+ int res = (longer[longer.length-i] & 0xff) + carry;
+ carry = (res > 0xff) ? 1 : 0;
+ longer[longer.length-i] = (byte)res;
+ }
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void reseed(byte[] additionalInput)
+ {
+ // 1. seed_material = 0x01 || V || entropy_input || additional_input.
+ //
+ // 2. seed = Hash_df (seed_material, seedlen).
+ //
+ // 3. V = seed.
+ //
+ // 4. C = Hash_df ((0x00 || V), seedlen).
+ //
+ // 5. reseed_counter = 1.
+ //
+ // 6. Return V, C, and reseed_counter for the new_working_state.
+ //
+ // Comment: Precede with a byte of all zeros.
+ byte[] entropy = _entropySource.getEntropy();
+ byte[] seedMaterial = Arrays.concatenate(ONE, _V, entropy, additionalInput);
+ byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
+
+ _V = seed;
+ byte[] subV = new byte[_V.length + 1];
+ subV[0] = 0x00;
+ System.arraycopy(_V, 0, subV, 1, _V.length);
+ _C = Utils.hash_df(_digest, subV, _seedLength);
+
+ _reseedCounter = 1;
+ }
+
+ private byte[] hash(byte[] input)
+ {
+ _digest.update(input, 0, input.length);
+ byte[] hash = new byte[_digest.getDigestSize()];
+ _digest.doFinal(hash, 0);
+ return hash;
+ }
+
+ // 1. m = [requested_number_of_bits / outlen]
+ // 2. data = V.
+ // 3. W = the Null string.
+ // 4. For i = 1 to m
+ // 4.1 wi = Hash (data).
+ // 4.2 W = W || wi.
+ // 4.3 data = (data + 1) mod 2^seedlen
+ // .
+ // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
+ private byte[] hashgen(byte[] input, int lengthInBits)
+ {
+ int digestSize = _digest.getDigestSize();
+ int m = (lengthInBits / 8) / digestSize;
+
+ byte[] data = new byte[input.length];
+ System.arraycopy(input, 0, data, 0, input.length);
+
+ byte[] W = new byte[lengthInBits / 8];
+
+ byte[] dig;
+ for (int i = 0; i <= m; i++)
+ {
+ dig = hash(data);
+
+ int bytesToCopy = ((W.length - i * dig.length) > dig.length)
+ ? dig.length
+ : (W.length - i * dig.length);
+ System.arraycopy(dig, 0, W, i * dig.length, bytesToCopy);
+
+ addTo(data, ONE);
+ }
+
+ return W;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
new file mode 100644
index 00000000..93bc8945
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.prng.drbg;
+
+/**
+ * Interface to SP800-90A deterministic random bit generators.
+ */
+public interface SP80090DRBG
+{
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ int generate(byte[] output, byte[] additionalInput, boolean predictionResistant);
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ void reseed(byte[] additionalInput);
+}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
new file mode 100644
index 00000000..f7a41176
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
@@ -0,0 +1,103 @@
+package org.bouncycastle.crypto.prng.drbg;
+
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.util.Integers;
+
+class Utils
+{
+ static final Hashtable maxSecurityStrengths = new Hashtable();
+
+ static
+ {
+ maxSecurityStrengths.put("SHA-1", Integers.valueOf(128));
+
+ maxSecurityStrengths.put("SHA-224", Integers.valueOf(192));
+ maxSecurityStrengths.put("SHA-256", Integers.valueOf(256));
+ maxSecurityStrengths.put("SHA-384", Integers.valueOf(256));
+ maxSecurityStrengths.put("SHA-512", Integers.valueOf(256));
+
+ maxSecurityStrengths.put("SHA-512/224", Integers.valueOf(192));
+ maxSecurityStrengths.put("SHA-512/256", Integers.valueOf(256));
+ }
+
+ static int getMaxSecurityStrength(Digest d)
+ {
+ return ((Integer)maxSecurityStrengths.get(d.getAlgorithmName())).intValue();
+ }
+
+ static int getMaxSecurityStrength(Mac m)
+ {
+ String name = m.getAlgorithmName();
+
+ return ((Integer)maxSecurityStrengths.get(name.substring(0, name.indexOf("/")))).intValue();
+ }
+
+ /**
+ * Used by both Dual EC and Hash.
+ */
+ static byte[] hash_df(Digest digest, byte[] seedMaterial, int seedLength)
+ {
+ // 1. temp = the Null string.
+ // 2. .
+ // 3. counter = an 8-bit binary value representing the integer "1".
+ // 4. For i = 1 to len do
+ // Comment : In step 4.1, no_of_bits_to_return
+ // is used as a 32-bit string.
+ // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
+ // input_string).
+ // 4.2 counter = counter + 1.
+ // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
+ // 6. Return SUCCESS and requested_bits.
+ byte[] temp = new byte[(seedLength + 7) / 8];
+
+ int len = temp.length / digest.getDigestSize();
+ int counter = 1;
+
+ byte[] dig = new byte[digest.getDigestSize()];
+
+ for (int i = 0; i <= len; i++)
+ {
+ digest.update((byte)counter);
+
+ digest.update((byte)(seedLength >> 24));
+ digest.update((byte)(seedLength >> 16));
+ digest.update((byte)(seedLength >> 8));
+ digest.update((byte)seedLength);
+
+ digest.update(seedMaterial, 0, seedMaterial.length);
+
+ digest.doFinal(dig, 0);
+
+ int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
+ ? dig.length
+ : (temp.length - i * dig.length);
+ System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
+
+ counter++;
+ }
+
+ // do a left shift to get rid of excess bits.
+ if (seedLength % 8 != 0)
+ {
+ int shift = 8 - (seedLength % 8);
+ int carry = 0;
+
+ for (int i = 0; i != temp.length; i++)
+ {
+ int b = temp[i] & 0xff;
+ temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
+ carry = b;
+ }
+ }
+
+ return temp;
+ }
+
+ static boolean isTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.length > maxBytes;
+ }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html b/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html
new file mode 100644
index 00000000..c0061660
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+SP800-90A deterministic random bit generators, can be used stand alone or in conjunction with SP800SecureRandomBuilder class.
+</body>
+</html>
diff --git a/src/main/java/org/bouncycastle/crypto/prng/package.html b/src/main/java/org/bouncycastle/crypto/prng/package.html
index 99525fbf..bb583abd 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/package.html
+++ b/src/main/java/org/bouncycastle/crypto/prng/package.html
@@ -1,5 +1,5 @@
<html>
<body bgcolor="#ffffff">
-Lightweight psuedo-random number generators.
+Lightweight psuedo-random number generators and SecureRandom builders.
</body>
</html>
diff --git a/src/main/java/org/bouncycastle/crypto/random/DRBGProvider.java b/src/main/java/org/bouncycastle/crypto/random/DRBGProvider.java
deleted file mode 100644
index f1ef83b2..00000000
--- a/src/main/java/org/bouncycastle/crypto/random/DRBGProvider.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.bouncycastle.crypto.random;
-
-import org.bouncycastle.crypto.prng.SP80090DRBG;
-import org.bouncycastle.crypto.prng.EntropySource;
-
-interface DRBGProvider
-{
- SP80090DRBG get(EntropySource entropySource);
-}
diff --git a/src/main/java/org/bouncycastle/crypto/util/Pack.java b/src/main/java/org/bouncycastle/crypto/util/Pack.java
index b767cc9e..d2ce166b 100644
--- a/src/main/java/org/bouncycastle/crypto/util/Pack.java
+++ b/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -1,192 +1,192 @@
-package org.bouncycastle.crypto.util;
-
-public abstract class Pack
-{
- public static int bigEndianToInt(byte[] bs, int off)
- {
- int n = bs[ off] << 24;
- n |= (bs[++off] & 0xff) << 16;
- n |= (bs[++off] & 0xff) << 8;
- n |= (bs[++off] & 0xff);
- return n;
- }
-
- public static void bigEndianToInt(byte[] bs, int off, int[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = bigEndianToInt(bs, off);
- off += 4;
- }
- }
-
- public static byte[] intToBigEndian(int n)
- {
- byte[] bs = new byte[4];
- intToBigEndian(n, bs, 0);
- return bs;
- }
-
- public static void intToBigEndian(int n, byte[] bs, int off)
- {
- bs[ off] = (byte)(n >>> 24);
- bs[++off] = (byte)(n >>> 16);
- bs[++off] = (byte)(n >>> 8);
- bs[++off] = (byte)(n );
- }
-
- public static byte[] intToBigEndian(int[] ns)
- {
- byte[] bs = new byte[4 * ns.length];
- intToBigEndian(ns, bs, 0);
- return bs;
- }
-
- public static void intToBigEndian(int[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- intToBigEndian(ns[i], bs, off);
- off += 4;
- }
- }
-
- public static long bigEndianToLong(byte[] bs, int off)
- {
- int hi = bigEndianToInt(bs, off);
- int lo = bigEndianToInt(bs, off + 4);
- return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
- }
-
- public static void bigEndianToLong(byte[] bs, int off, long[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = bigEndianToLong(bs, off);
- off += 8;
- }
- }
-
- public static byte[] longToBigEndian(long n)
- {
- byte[] bs = new byte[8];
- longToBigEndian(n, bs, 0);
- return bs;
- }
-
- public static void longToBigEndian(long n, byte[] bs, int off)
- {
- intToBigEndian((int)(n >>> 32), bs, off);
- intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
- }
-
- public static byte[] longToBigEndian(long[] ns)
- {
- byte[] bs = new byte[8 * ns.length];
- longToBigEndian(ns, bs, 0);
- return bs;
- }
-
- public static void longToBigEndian(long[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- longToBigEndian(ns[i], bs, off);
- off += 8;
- }
- }
-
- public static int littleEndianToInt(byte[] bs, int off)
- {
- int n = bs[ off] & 0xff;
- n |= (bs[++off] & 0xff) << 8;
- n |= (bs[++off] & 0xff) << 16;
- n |= bs[++off] << 24;
- return n;
- }
-
- public static void littleEndianToInt(byte[] bs, int off, int[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = littleEndianToInt(bs, off);
- off += 4;
- }
- }
-
- public static byte[] intToLittleEndian(int n)
- {
- byte[] bs = new byte[4];
- intToLittleEndian(n, bs, 0);
- return bs;
- }
-
- public static void intToLittleEndian(int n, byte[] bs, int off)
- {
- bs[ off] = (byte)(n );
- bs[++off] = (byte)(n >>> 8);
- bs[++off] = (byte)(n >>> 16);
- bs[++off] = (byte)(n >>> 24);
- }
-
- public static byte[] intToLittleEndian(int[] ns)
- {
- byte[] bs = new byte[4 * ns.length];
- intToLittleEndian(ns, bs, 0);
- return bs;
- }
-
- public static void intToLittleEndian(int[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- intToLittleEndian(ns[i], bs, off);
- off += 4;
- }
- }
-
- public static long littleEndianToLong(byte[] bs, int off)
- {
- int lo = littleEndianToInt(bs, off);
- int hi = littleEndianToInt(bs, off + 4);
- return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
- }
-
- public static void littleEndianToLong(byte[] bs, int off, long[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = littleEndianToLong(bs, off);
- off += 8;
- }
- }
-
- public static byte[] longToLittleEndian(long n)
- {
- byte[] bs = new byte[8];
- longToLittleEndian(n, bs, 0);
- return bs;
- }
-
- public static void longToLittleEndian(long n, byte[] bs, int off)
- {
- intToLittleEndian((int)(n & 0xffffffffL), bs, off);
- intToLittleEndian((int)(n >>> 32), bs, off + 4);
- }
-
- public static byte[] longToLittleEndian(long[] ns)
- {
- byte[] bs = new byte[8 * ns.length];
- longToLittleEndian(ns, bs, 0);
- return bs;
- }
-
- public static void longToLittleEndian(long[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- longToLittleEndian(ns[i], bs, off);
- off += 8;
- }
- }
-}
+package org.bouncycastle.crypto.util;
+
+public abstract class Pack
+{
+ public static int bigEndianToInt(byte[] bs, int off)
+ {
+ int n = bs[ off] << 24;
+ n |= (bs[++off] & 0xff) << 16;
+ n |= (bs[++off] & 0xff) << 8;
+ n |= (bs[++off] & 0xff);
+ return n;
+ }
+
+ public static void bigEndianToInt(byte[] bs, int off, int[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = bigEndianToInt(bs, off);
+ off += 4;
+ }
+ }
+
+ public static byte[] intToBigEndian(int n)
+ {
+ byte[] bs = new byte[4];
+ intToBigEndian(n, bs, 0);
+ return bs;
+ }
+
+ public static void intToBigEndian(int n, byte[] bs, int off)
+ {
+ bs[ off] = (byte)(n >>> 24);
+ bs[++off] = (byte)(n >>> 16);
+ bs[++off] = (byte)(n >>> 8);
+ bs[++off] = (byte)(n );
+ }
+
+ public static byte[] intToBigEndian(int[] ns)
+ {
+ byte[] bs = new byte[4 * ns.length];
+ intToBigEndian(ns, bs, 0);
+ return bs;
+ }
+
+ public static void intToBigEndian(int[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ intToBigEndian(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ public static long bigEndianToLong(byte[] bs, int off)
+ {
+ int hi = bigEndianToInt(bs, off);
+ int lo = bigEndianToInt(bs, off + 4);
+ return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+ }
+
+ public static void bigEndianToLong(byte[] bs, int off, long[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = bigEndianToLong(bs, off);
+ off += 8;
+ }
+ }
+
+ public static byte[] longToBigEndian(long n)
+ {
+ byte[] bs = new byte[8];
+ longToBigEndian(n, bs, 0);
+ return bs;
+ }
+
+ public static void longToBigEndian(long n, byte[] bs, int off)
+ {
+ intToBigEndian((int)(n >>> 32), bs, off);
+ intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
+ }
+
+ public static byte[] longToBigEndian(long[] ns)
+ {
+ byte[] bs = new byte[8 * ns.length];
+ longToBigEndian(ns, bs, 0);
+ return bs;
+ }
+
+ public static void longToBigEndian(long[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ longToBigEndian(ns[i], bs, off);
+ off += 8;
+ }
+ }
+
+ public static int littleEndianToInt(byte[] bs, int off)
+ {
+ int n = bs[ off] & 0xff;
+ n |= (bs[++off] & 0xff) << 8;
+ n |= (bs[++off] & 0xff) << 16;
+ n |= bs[++off] << 24;
+ return n;
+ }
+
+ public static void littleEndianToInt(byte[] bs, int off, int[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = littleEndianToInt(bs, off);
+ off += 4;
+ }
+ }
+
+ public static byte[] intToLittleEndian(int n)
+ {
+ byte[] bs = new byte[4];
+ intToLittleEndian(n, bs, 0);
+ return bs;
+ }
+
+ public static void intToLittleEndian(int n, byte[] bs, int off)
+ {
+ bs[ off] = (byte)(n );
+ bs[++off] = (byte)(n >>> 8);
+ bs[++off] = (byte)(n >>> 16);
+ bs[++off] = (byte)(n >>> 24);
+ }
+
+ public static byte[] intToLittleEndian(int[] ns)
+ {
+ byte[] bs = new byte[4 * ns.length];
+ intToLittleEndian(ns, bs, 0);
+ return bs;
+ }
+
+ public static void intToLittleEndian(int[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ intToLittleEndian(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ public static long littleEndianToLong(byte[] bs, int off)
+ {
+ int lo = littleEndianToInt(bs, off);
+ int hi = littleEndianToInt(bs, off + 4);
+ return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+ }
+
+ public static void littleEndianToLong(byte[] bs, int off, long[] ns)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = littleEndianToLong(bs, off);
+ off += 8;
+ }
+ }
+
+ public static byte[] longToLittleEndian(long n)
+ {
+ byte[] bs = new byte[8];
+ longToLittleEndian(n, bs, 0);
+ return bs;
+ }
+
+ public static void longToLittleEndian(long n, byte[] bs, int off)
+ {
+ intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+ intToLittleEndian((int)(n >>> 32), bs, off + 4);
+ }
+
+ public static byte[] longToLittleEndian(long[] ns)
+ {
+ byte[] bs = new byte[8 * ns.length];
+ longToLittleEndian(ns, bs, 0);
+ return bs;
+ }
+
+ public static void longToLittleEndian(long[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.length; ++i)
+ {
+ longToLittleEndian(ns[i], bs, off);
+ off += 8;
+ }
+ }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
index 31226180..4c2ca28b 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -82,6 +82,8 @@ public class EC
addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+ addSignatureAlgorithm(provider, "SHA384", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+ addSignatureAlgorithm(provider, "SHA512", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
index 2e5ee565..d850e5de 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
@@ -7,25 +7,36 @@ import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-//import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-//import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
public class AlgorithmParameterGeneratorSpi
extends java.security.AlgorithmParameterGeneratorSpi
{
protected SecureRandom random;
protected int strength = 1024;
+ protected DSAParameterGenerationParameters params;
protected void engineInit(
int strength,
SecureRandom random)
{
- if (strength < 512 || strength > 1024 || strength % 64 != 0)
+ if (strength < 512 || strength > 3072)
{
- throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+ throw new InvalidParameterException("strength must be from 512 - 3072");
+ }
+
+ if (strength <= 1024 && strength % 64 != 0)
+ {
+ throw new InvalidParameterException("strength must be a multiple of 64 below 1024 bits.");
+ }
+
+ if (strength > 1024 && strength % 1024 != 0)
+ {
+ throw new InvalidParameterException("strength must be a multiple of 1024 above 1024 bits.");
}
this.strength = strength;
@@ -42,15 +53,35 @@ public class AlgorithmParameterGeneratorSpi
protected AlgorithmParameters engineGenerateParameters()
{
- DSAParametersGenerator pGen = new DSAParametersGenerator();
+ DSAParametersGenerator pGen;
- if (random != null)
+ if (strength <= 1024)
{
- pGen.init(strength, 20, random);
+ pGen = new DSAParametersGenerator();
}
else
{
- pGen.init(strength, 20, new SecureRandom());
+ pGen = new DSAParametersGenerator(new SHA256Digest());
+ }
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (strength == 1024)
+ {
+ params = new DSAParameterGenerationParameters(1024, 160, 80, random);
+ pGen.init(params);
+ }
+ else if (strength > 1024)
+ {
+ params = new DSAParameterGenerationParameters(strength, 256, 80, random);
+ pGen.init(params);
+ }
+ else
+ {
+ pGen.init(strength, 20, random);
}
DSAParameters p = pGen.generateParameters();
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
index 8c8a5b9e..ef12b4f5 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -52,11 +52,6 @@ public class DSASigner
{
CipherParameters param;
-// if (publicKey instanceof GOST3410Key)
-// {
-// param = GOST3410Util.generatePublicKeyParameter(publicKey);
-// }
-// else if (publicKey instanceof DSAKey)
if (publicKey instanceof DSAKey)
{
param = DSAUtil.generatePublicKeyParameter(publicKey);
@@ -103,14 +98,7 @@ public class DSASigner
{
CipherParameters param;
-// if (privateKey instanceof GOST3410Key)
-// {
-// param = GOST3410Util.generatePrivateKeyParameter(privateKey);
-// }
-// else
-// {
- param = DSAUtil.generatePrivateKeyParameter(privateKey);
-// }
+ param = DSAUtil.generatePrivateKeyParameter(privateKey);
if (random != null)
{
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
index 8fc79b86..fc3a8bb7 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -199,6 +199,24 @@ public class SignatureSpi
}
}
+ static public class ecCVCDSA384
+ extends SignatureSpi
+ {
+ public ecCVCDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA512
+ extends SignatureSpi
+ {
+ public ecCVCDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
private static class StdDSAEncoder
implements DSAEncoder
{
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
index ad7483a4..44220622 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
@@ -66,7 +66,7 @@ import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.encoders.Hex;
-class X509CertificateObject
+class X509CertificateObject
extends X509Certificate
implements PKCS12BagAttributeCarrier
{
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
index 07f47ead..7a6f7b04 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -16,8 +16,10 @@ import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.engines.AESWrapEngine;
import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
import org.bouncycastle.crypto.macs.CMac;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
@@ -28,7 +30,6 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class AES
@@ -88,6 +89,15 @@ public final class AES
}
}
+ public static class AESGMAC
+ extends BaseMac
+ {
+ public AESGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new AESFastEngine())));
+ }
+ }
+
static public class Wrap
extends BaseWrapCipher
{
@@ -159,7 +169,6 @@ public final class AES
super(256);
}
}
-
/**
* PBEWithSHA1And128BitAES-BC
@@ -317,7 +326,7 @@ public final class AES
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = AES.class.getName();
@@ -473,6 +482,8 @@ public final class AES
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+
+ addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
index 9ac54e73..68605f45 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
@@ -2,10 +2,12 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.CAST6Engine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
public final class CAST6
{
@@ -31,8 +33,17 @@ public final class CAST6
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CAST6Engine())));
+ }
+ }
+
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = CAST6.class.getName();
@@ -44,6 +55,8 @@ public final class CAST6
{
provider.addAlgorithm("Cipher.CAST6", PREFIX + "$ECB");
provider.addAlgorithm("KeyGenerator.CAST6", PREFIX + "$KeyGen");
+
+ addGMacAlgorithm(provider, "CAST6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
index 5c98e961..38b5ca7b 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
@@ -13,15 +13,17 @@ import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.CamelliaEngine;
import org.bouncycastle.crypto.engines.CamelliaWrapEngine;
import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class Camellia
@@ -72,6 +74,15 @@ public final class Camellia
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CamelliaEngine())));
+ }
+ }
+
public static class KeyGen
extends BaseKeyGenerator
{
@@ -161,7 +172,7 @@ public final class Camellia
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Camellia.class.getName();
@@ -201,6 +212,7 @@ public final class Camellia
provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia192_cbc, PREFIX + "$KeyGen192");
provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia256_cbc, PREFIX + "$KeyGen256");
+ addGMacAlgorithm(provider, "CAMELLIA", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
index 67908f9d..0f53e504 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -366,6 +366,13 @@ public final class DESede
provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, PREFIX + "$Wrap");
provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
+ provider.addAlgorithm("Alg.Alias.Cipher.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.Cipher.TDEAWRAP", "DESEDEWRAP");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
+
if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
{
provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
index d488ac2c..2d089cc7 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
@@ -9,12 +9,14 @@ import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.NoekeonEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class Noekeon
@@ -41,6 +43,15 @@ public final class Noekeon
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new NoekeonEngine())));
+ }
+ }
+
public static class AlgParamGen
extends BaseAlgorithmParameterGenerator
{
@@ -89,7 +100,7 @@ public final class Noekeon
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Noekeon.class.getName();
@@ -108,6 +119,7 @@ public final class Noekeon
provider.addAlgorithm("KeyGenerator.NOEKEON", PREFIX + "$KeyGen");
+ addGMacAlgorithm(provider, "NOEKEON", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
index 0861f13b..a29e717c 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
@@ -11,16 +11,18 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.RC6Engine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class RC6
@@ -71,6 +73,15 @@ public final class RC6
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new RC6Engine())));
+ }
+ }
+
public static class KeyGen
extends BaseKeyGenerator
{
@@ -128,7 +139,7 @@ public final class RC6
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = RC6.class.getName();
@@ -143,6 +154,7 @@ public final class RC6
provider.addAlgorithm("KeyGenerator.RC6", PREFIX + "$KeyGen");
provider.addAlgorithm("AlgorithmParameters.RC6", PREFIX + "$AlgParams");
+ addGMacAlgorithm(provider, "RC6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
index e4cffe30..2ad41bff 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
@@ -12,15 +12,17 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.engines.SEEDWrapEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class SEED
@@ -71,6 +73,15 @@ public final class SEED
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SEEDEngine())));
+ }
+ }
+
public static class AlgParamGen
extends BaseAlgorithmParameterGenerator
{
@@ -119,7 +130,7 @@ public final class SEED
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = SEED.class.getName();
@@ -146,6 +157,7 @@ public final class SEED
provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_seedCBC, PREFIX + "$KeyGen");
provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, PREFIX + "$KeyGen");
+ addGMacAlgorithm(provider, "SEED", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
index 02959ec4..578de32d 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
@@ -3,12 +3,14 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.SerpentEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
public final class Serpent
{
@@ -40,6 +42,15 @@ public final class Serpent
}
}
+ public static class SerpentGMAC
+ extends BaseMac
+ {
+ public SerpentGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SerpentEngine())));
+ }
+ }
+
public static class AlgParams
extends IvAlgorithmParameters
{
@@ -50,7 +61,7 @@ public final class Serpent
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Serpent.class.getName();
@@ -65,6 +76,7 @@ public final class Serpent
provider.addAlgorithm("KeyGenerator.Serpent", PREFIX + "$KeyGen");
provider.addAlgorithm("AlgorithmParameters.Serpent", PREFIX + "$AlgParams");
+ addGMacAlgorithm(provider, "SERPENT", PREFIX + "$SerpentGMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
new file mode 100644
index 00000000..49656c27
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class SymmetricAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addGMacAlgorithm(
+ ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ provider.addAlgorithm("Mac." + algorithm + "-GMAC", algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "GMAC", algorithm + "-GMAC");
+
+ provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC", algorithm + "-GMAC");
+ }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
index 604e7663..67b9f663 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
@@ -3,14 +3,16 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.TwofishEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
public final class Twofish
{
@@ -42,6 +44,14 @@ public final class Twofish
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new TwofishEngine())));
+ }
+ }
/**
* PBEWithSHAAndTwofish-CBC
@@ -77,7 +87,7 @@ public final class Twofish
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Twofish.class.getName();
@@ -95,6 +105,8 @@ public final class Twofish
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
provider.addAlgorithm("Cipher.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHA");
provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHAKeyFactory");
+
+ addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
index ac67152a..cbc5aaf4 100644
--- a/src/main/java/org/bouncycastle/math/ec/ECPoint.java
+++ b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -1,593 +1,593 @@
-package org.bouncycastle.math.ec;
-
-import java.math.BigInteger;
-
-import org.bouncycastle.asn1.x9.X9IntegerConverter;
-
-/**
- * base class for points on elliptic curves.
- */
-public abstract class ECPoint
-{
- ECCurve curve;
- ECFieldElement x;
- ECFieldElement y;
-
- protected boolean withCompression;
-
- protected ECMultiplier multiplier = null;
-
- protected PreCompInfo preCompInfo = null;
-
- private static X9IntegerConverter converter = new X9IntegerConverter();
-
- protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
- {
- this.curve = curve;
- this.x = x;
- this.y = y;
- }
-
- public ECCurve getCurve()
- {
- return curve;
- }
-
- public ECFieldElement getX()
- {
- return x;
- }
-
- public ECFieldElement getY()
- {
- return y;
- }
-
- public boolean isInfinity()
- {
- return x == null && y == null;
- }
-
- public boolean isCompressed()
- {
- return withCompression;
- }
-
- public boolean equals(
- Object other)
- {
- if (other == this)
- {
- return true;
- }
-
- if (!(other instanceof ECPoint))
- {
- return false;
- }
-
- ECPoint o = (ECPoint)other;
-
- if (this.isInfinity())
- {
- return o.isInfinity();
- }
-
- return x.equals(o.x) && y.equals(o.y);
- }
-
- public int hashCode()
- {
- if (this.isInfinity())
- {
- return 0;
- }
-
- return x.hashCode() ^ y.hashCode();
- }
-
-// /**
-// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
-// * @param multiplier The <code>ECMultiplier</code> to be used to multiply
-// * this <code>ECPoint</code>.
-// */
-// public void setECMultiplier(ECMultiplier multiplier)
-// {
-// this.multiplier = multiplier;
-// }
-
- /**
- * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
- * to save the precomputation for this <code>ECPoint</code> to store the
- * precomputation result for use by subsequent multiplication.
- * @param preCompInfo The values precomputed by the
- * <code>ECMultiplier</code>.
- */
- void setPreCompInfo(PreCompInfo preCompInfo)
- {
- this.preCompInfo = preCompInfo;
- }
-
- public byte[] getEncoded()
- {
- return getEncoded(withCompression);
- }
-
- public abstract byte[] getEncoded(boolean compressed);
-
- public abstract ECPoint add(ECPoint b);
- public abstract ECPoint subtract(ECPoint b);
- public abstract ECPoint negate();
- public abstract ECPoint twice();
-
- /**
- * Sets the default <code>ECMultiplier</code>, unless already set.
- */
- synchronized void assertECMultiplier()
- {
- if (this.multiplier == null)
- {
- this.multiplier = new FpNafMultiplier();
- }
- }
-
- /**
- * Multiplies this <code>ECPoint</code> by the given number.
- * @param k The multiplicator.
- * @return <code>k * this</code>.
- */
- public ECPoint multiply(BigInteger k)
- {
- if (k.signum() < 0)
- {
- throw new IllegalArgumentException("The multiplicator cannot be negative");
- }
-
- if (this.isInfinity())
- {
- return this;
- }
-
- if (k.signum() == 0)
- {
- return this.curve.getInfinity();
- }
-
- assertECMultiplier();
- return this.multiplier.multiply(this, k, preCompInfo);
- }
-
- /**
- * Elliptic curve points over Fp
- */
- public static class Fp extends ECPoint
- {
-
- /**
- * Create a point which encodes with point compression.
- *
- * @param curve the curve to use
- * @param x affine x co-ordinate
- * @param y affine y co-ordinate
- */
- public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
- {
- this(curve, x, y, false);
- }
-
- /**
- * Create a point that encodes with or without point compresion.
- *
- * @param curve the curve to use
- * @param x affine x co-ordinate
- * @param y affine y co-ordinate
- * @param withCompression if true encode with point compression
- */
- public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
- {
- super(curve, x, y);
-
- if ((x != null && y == null) || (x == null && y != null))
- {
- throw new IllegalArgumentException("Exactly one of the field elements is null");
- }
-
- this.withCompression = withCompression;
- }
-
- /**
- * return the field element encoded with point compression. (S 4.3.6)
- */
- public byte[] getEncoded(boolean compressed)
- {
- if (this.isInfinity())
- {
- return new byte[1];
- }
-
- int qLength = converter.getByteLength(x);
-
- if (compressed)
- {
- byte PC;
-
- if (this.getY().toBigInteger().testBit(0))
- {
- PC = 0x03;
- }
- else
- {
- PC = 0x02;
- }
-
- byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
- byte[] PO = new byte[X.length + 1];
-
- PO[0] = PC;
- System.arraycopy(X, 0, PO, 1, X.length);
-
- return PO;
- }
- else
- {
- byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
- byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
- byte[] PO = new byte[X.length + Y.length + 1];
-
- PO[0] = 0x04;
- System.arraycopy(X, 0, PO, 1, X.length);
- System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
-
- return PO;
- }
- }
-
- // B.3 pg 62
- public ECPoint add(ECPoint b)
- {
- if (this.isInfinity())
- {
- return b;
- }
-
- if (b.isInfinity())
- {
- return this;
- }
-
- // Check if b = this or b = -this
- if (this.x.equals(b.x))
- {
- if (this.y.equals(b.y))
- {
- // this = b, i.e. this must be doubled
- return this.twice();
- }
-
- // this = -b, i.e. the result is the point at infinity
- return this.curve.getInfinity();
- }
-
- ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
-
- ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
- ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
-
- return new ECPoint.Fp(curve, x3, y3, withCompression);
- }
-
- // B.3 pg 62
- public ECPoint twice()
- {
- if (this.isInfinity())
- {
- // Twice identity element (point at infinity) is identity
- return this;
- }
-
- if (this.y.toBigInteger().signum() == 0)
- {
- // if y1 == 0, then (x1, y1) == (x1, -y1)
- // and hence this = -this and thus 2(x1, y1) == infinity
- return this.curve.getInfinity();
- }
-
- ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
- ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
- ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
-
- ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
- ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
-
- return new ECPoint.Fp(curve, x3, y3, this.withCompression);
- }
-
- // D.3.2 pg 102 (see Note:)
- public ECPoint subtract(ECPoint b)
- {
- if (b.isInfinity())
- {
- return this;
- }
-
- // Add -b
- return add(b.negate());
- }
-
- public ECPoint negate()
- {
- return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
- }
-
- /**
- * Sets the default <code>ECMultiplier</code>, unless already set.
- */
- synchronized void assertECMultiplier()
- {
- if (this.multiplier == null)
- {
- this.multiplier = new WNafMultiplier();
- }
- }
- }
-
- /**
- * Elliptic curve points over F2m
- */
- public static class F2m extends ECPoint
- {
- /**
- * @param curve base curve
- * @param x x point
- * @param y y point
- */
- public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
- {
- this(curve, x, y, false);
- }
-
- /**
- * @param curve base curve
- * @param x x point
- * @param y y point
- * @param withCompression true if encode with point compression.
- */
- public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
- {
- super(curve, x, y);
-
- if ((x != null && y == null) || (x == null && y != null))
- {
- throw new IllegalArgumentException("Exactly one of the field elements is null");
- }
-
- if (x != null)
- {
- // Check if x and y are elements of the same field
- ECFieldElement.F2m.checkFieldElements(this.x, this.y);
-
- // Check if x and a are elements of the same field
- if (curve != null)
- {
- ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
- }
- }
-
- this.withCompression = withCompression;
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
- */
- public byte[] getEncoded(boolean compressed)
- {
- if (this.isInfinity())
- {
- return new byte[1];
- }
-
- int byteCount = converter.getByteLength(this.x);
- byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
- byte[] PO;
-
- if (compressed)
- {
- // See X9.62 4.3.6 and 4.2.2
- PO = new byte[byteCount + 1];
-
- PO[0] = 0x02;
- // X9.62 4.2.2 and 4.3.6:
- // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
- // bit of y * x^(-1)
- // if ypTilde = 0, then PC := 02, else PC := 03
- // Note: PC === PO[0]
- if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
- {
- if (this.getY().multiply(this.getX().invert())
- .toBigInteger().testBit(0))
- {
- // ypTilde = 1, hence PC = 03
- PO[0] = 0x03;
- }
- }
-
- System.arraycopy(X, 0, PO, 1, byteCount);
- }
- else
- {
- byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
-
- PO = new byte[byteCount + byteCount + 1];
-
- PO[0] = 0x04;
- System.arraycopy(X, 0, PO, 1, byteCount);
- System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
- }
-
- return PO;
- }
-
- /**
- * Check, if two <code>ECPoint</code>s can be added or subtracted.
- * @param a The first <code>ECPoint</code> to check.
- * @param b The second <code>ECPoint</code> to check.
- * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
- * cannot be added.
- */
- private static void checkPoints(ECPoint a, ECPoint b)
- {
- // Check, if points are on the same curve
- if (!(a.curve.equals(b.curve)))
- {
- throw new IllegalArgumentException("Only points on the same "
- + "curve can be added or subtracted");
- }
-
-// ECFieldElement.F2m.checkFieldElements(a.x, b.x);
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
- */
- public ECPoint add(ECPoint b)
- {
- checkPoints(this, b);
- return addSimple((ECPoint.F2m)b);
- }
-
- /**
- * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
- * checking if both points are on the same curve. Used by multiplication
- * algorithms, because there all points are a multiple of the same point
- * and hence the checks can be omitted.
- * @param b The other <code>ECPoints.F2m</code> to add to
- * <code>this</code>.
- * @return <code>this + b</code>
- */
- public ECPoint.F2m addSimple(ECPoint.F2m b)
- {
- ECPoint.F2m other = b;
- if (this.isInfinity())
- {
- return other;
- }
-
- if (other.isInfinity())
- {
- return this;
- }
-
- ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
- ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
-
- // Check if other = this or other = -this
- if (this.x.equals(x2))
- {
- if (this.y.equals(y2))
- {
- // this = other, i.e. this must be doubled
- return (ECPoint.F2m)this.twice();
- }
-
- // this = -other, i.e. the result is the point at infinity
- return (ECPoint.F2m)this.curve.getInfinity();
- }
-
- ECFieldElement.F2m lambda
- = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
-
- ECFieldElement.F2m x3
- = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
-
- ECFieldElement.F2m y3
- = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
-
- return new ECPoint.F2m(curve, x3, y3, withCompression);
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
- */
- public ECPoint subtract(ECPoint b)
- {
- checkPoints(this, b);
- return subtractSimple((ECPoint.F2m)b);
- }
-
- /**
- * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
- * without checking if both points are on the same curve. Used by
- * multiplication algorithms, because there all points are a multiple
- * of the same point and hence the checks can be omitted.
- * @param b The other <code>ECPoints.F2m</code> to subtract from
- * <code>this</code>.
- * @return <code>this - b</code>
- */
- public ECPoint.F2m subtractSimple(ECPoint.F2m b)
- {
- if (b.isInfinity())
- {
- return this;
- }
-
- // Add -b
- return addSimple((ECPoint.F2m)b.negate());
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#twice()
- */
- public ECPoint twice()
- {
- if (this.isInfinity())
- {
- // Twice identity element (point at infinity) is identity
- return this;
- }
-
- if (this.x.toBigInteger().signum() == 0)
- {
- // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
- // and hence this = -this and thus 2(x1, y1) == infinity
- return this.curve.getInfinity();
- }
-
- ECFieldElement.F2m lambda
- = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
-
- ECFieldElement.F2m x3
- = (ECFieldElement.F2m)lambda.square().add(lambda).
- add(this.curve.getA());
-
- ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
- ECFieldElement.F2m y3
- = (ECFieldElement.F2m)this.x.square().add(
- x3.multiply(lambda.add(ONE)));
-
- return new ECPoint.F2m(this.curve, x3, y3, withCompression);
- }
-
- public ECPoint negate()
- {
- return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
- }
-
- /**
- * Sets the appropriate <code>ECMultiplier</code>, unless already set.
- */
- synchronized void assertECMultiplier()
- {
- if (this.multiplier == null)
- {
- if (((ECCurve.F2m)this.curve).isKoblitz())
- {
- this.multiplier = new WTauNafMultiplier();
- }
- else
- {
- this.multiplier = new WNafMultiplier();
- }
- }
- }
- }
-}
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+
+/**
+ * base class for points on elliptic curves.
+ */
+public abstract class ECPoint
+{
+ ECCurve curve;
+ ECFieldElement x;
+ ECFieldElement y;
+
+ protected boolean withCompression;
+
+ protected ECMultiplier multiplier = null;
+
+ protected PreCompInfo preCompInfo = null;
+
+ private static X9IntegerConverter converter = new X9IntegerConverter();
+
+ protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this.curve = curve;
+ this.x = x;
+ this.y = y;
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECFieldElement getX()
+ {
+ return x;
+ }
+
+ public ECFieldElement getY()
+ {
+ return y;
+ }
+
+ public boolean isInfinity()
+ {
+ return x == null && y == null;
+ }
+
+ public boolean isCompressed()
+ {
+ return withCompression;
+ }
+
+ public boolean equals(
+ Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof ECPoint))
+ {
+ return false;
+ }
+
+ ECPoint o = (ECPoint)other;
+
+ if (this.isInfinity())
+ {
+ return o.isInfinity();
+ }
+
+ return x.equals(o.x) && y.equals(o.y);
+ }
+
+ public int hashCode()
+ {
+ if (this.isInfinity())
+ {
+ return 0;
+ }
+
+ return x.hashCode() ^ y.hashCode();
+ }
+
+// /**
+// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
+// * @param multiplier The <code>ECMultiplier</code> to be used to multiply
+// * this <code>ECPoint</code>.
+// */
+// public void setECMultiplier(ECMultiplier multiplier)
+// {
+// this.multiplier = multiplier;
+// }
+
+ /**
+ * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
+ * to save the precomputation for this <code>ECPoint</code> to store the
+ * precomputation result for use by subsequent multiplication.
+ * @param preCompInfo The values precomputed by the
+ * <code>ECMultiplier</code>.
+ */
+ void setPreCompInfo(PreCompInfo preCompInfo)
+ {
+ this.preCompInfo = preCompInfo;
+ }
+
+ public byte[] getEncoded()
+ {
+ return getEncoded(withCompression);
+ }
+
+ public abstract byte[] getEncoded(boolean compressed);
+
+ public abstract ECPoint add(ECPoint b);
+ public abstract ECPoint subtract(ECPoint b);
+ public abstract ECPoint negate();
+ public abstract ECPoint twice();
+
+ /**
+ * Sets the default <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new FpNafMultiplier();
+ }
+ }
+
+ /**
+ * Multiplies this <code>ECPoint</code> by the given number.
+ * @param k The multiplicator.
+ * @return <code>k * this</code>.
+ */
+ public ECPoint multiply(BigInteger k)
+ {
+ if (k.signum() < 0)
+ {
+ throw new IllegalArgumentException("The multiplicator cannot be negative");
+ }
+
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ if (k.signum() == 0)
+ {
+ return this.curve.getInfinity();
+ }
+
+ assertECMultiplier();
+ return this.multiplier.multiply(this, k, preCompInfo);
+ }
+
+ /**
+ * Elliptic curve points over Fp
+ */
+ public static class Fp extends ECPoint
+ {
+
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ */
+ public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this(curve, x, y, false);
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ * @param withCompression if true encode with point compression
+ */
+ public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /**
+ * return the field element encoded with point compression. (S 4.3.6)
+ */
+ public byte[] getEncoded(boolean compressed)
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int qLength = converter.getByteLength(x);
+
+ if (compressed)
+ {
+ byte PC;
+
+ if (this.getY().toBigInteger().testBit(0))
+ {
+ PC = 0x03;
+ }
+ else
+ {
+ PC = 0x02;
+ }
+
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + 1];
+
+ PO[0] = PC;
+ System.arraycopy(X, 0, PO, 1, X.length);
+
+ return PO;
+ }
+ else
+ {
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + Y.length + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, X.length);
+ System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+
+ return PO;
+ }
+ }
+
+ // B.3 pg 62
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Check if b = this or b = -this
+ if (this.x.equals(b.x))
+ {
+ if (this.y.equals(b.y))
+ {
+ // this = b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this = -b, i.e. the result is the point at infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3, withCompression);
+ }
+
+ // B.3 pg 62
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.y.toBigInteger().signum() == 0)
+ {
+ // if y1 == 0, then (x1, y1) == (x1, -y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
+ ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
+ ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3, this.withCompression);
+ }
+
+ // D.3.2 pg 102 (see Note:)
+ public ECPoint subtract(ECPoint b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return add(b.negate());
+ }
+
+ public ECPoint negate()
+ {
+ return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
+ }
+
+ /**
+ * Sets the default <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+
+ /**
+ * Elliptic curve points over F2m
+ */
+ public static class F2m extends ECPoint
+ {
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this(curve, x, y, false);
+ }
+
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ * @param withCompression true if encode with point compression.
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ if (x != null)
+ {
+ // Check if x and y are elements of the same field
+ ECFieldElement.F2m.checkFieldElements(this.x, this.y);
+
+ // Check if x and a are elements of the same field
+ if (curve != null)
+ {
+ ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
+ }
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
+ */
+ public byte[] getEncoded(boolean compressed)
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int byteCount = converter.getByteLength(this.x);
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
+ byte[] PO;
+
+ if (compressed)
+ {
+ // See X9.62 4.3.6 and 4.2.2
+ PO = new byte[byteCount + 1];
+
+ PO[0] = 0x02;
+ // X9.62 4.2.2 and 4.3.6:
+ // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
+ // bit of y * x^(-1)
+ // if ypTilde = 0, then PC := 02, else PC := 03
+ // Note: PC === PO[0]
+ if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
+ {
+ if (this.getY().multiply(this.getX().invert())
+ .toBigInteger().testBit(0))
+ {
+ // ypTilde = 1, hence PC = 03
+ PO[0] = 0x03;
+ }
+ }
+
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ }
+ else
+ {
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
+
+ PO = new byte[byteCount + byteCount + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
+ }
+
+ return PO;
+ }
+
+ /**
+ * Check, if two <code>ECPoint</code>s can be added or subtracted.
+ * @param a The first <code>ECPoint</code> to check.
+ * @param b The second <code>ECPoint</code> to check.
+ * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+ * cannot be added.
+ */
+ private static void checkPoints(ECPoint a, ECPoint b)
+ {
+ // Check, if points are on the same curve
+ if (!(a.curve.equals(b.curve)))
+ {
+ throw new IllegalArgumentException("Only points on the same "
+ + "curve can be added or subtracted");
+ }
+
+// ECFieldElement.F2m.checkFieldElements(a.x, b.x);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
+ */
+ public ECPoint add(ECPoint b)
+ {
+ checkPoints(this, b);
+ return addSimple((ECPoint.F2m)b);
+ }
+
+ /**
+ * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
+ * checking if both points are on the same curve. Used by multiplication
+ * algorithms, because there all points are a multiple of the same point
+ * and hence the checks can be omitted.
+ * @param b The other <code>ECPoints.F2m</code> to add to
+ * <code>this</code>.
+ * @return <code>this + b</code>
+ */
+ public ECPoint.F2m addSimple(ECPoint.F2m b)
+ {
+ ECPoint.F2m other = b;
+ if (this.isInfinity())
+ {
+ return other;
+ }
+
+ if (other.isInfinity())
+ {
+ return this;
+ }
+
+ ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
+ ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
+
+ // Check if other = this or other = -this
+ if (this.x.equals(x2))
+ {
+ if (this.y.equals(y2))
+ {
+ // this = other, i.e. this must be doubled
+ return (ECPoint.F2m)this.twice();
+ }
+
+ // this = -other, i.e. the result is the point at infinity
+ return (ECPoint.F2m)this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
+
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
+
+ return new ECPoint.F2m(curve, x3, y3, withCompression);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
+ */
+ public ECPoint subtract(ECPoint b)
+ {
+ checkPoints(this, b);
+ return subtractSimple((ECPoint.F2m)b);
+ }
+
+ /**
+ * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
+ * without checking if both points are on the same curve. Used by
+ * multiplication algorithms, because there all points are a multiple
+ * of the same point and hence the checks can be omitted.
+ * @param b The other <code>ECPoints.F2m</code> to subtract from
+ * <code>this</code>.
+ * @return <code>this - b</code>
+ */
+ public ECPoint.F2m subtractSimple(ECPoint.F2m b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return addSimple((ECPoint.F2m)b.negate());
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#twice()
+ */
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.x.toBigInteger().signum() == 0)
+ {
+ // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).
+ add(this.curve.getA());
+
+ ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)this.x.square().add(
+ x3.multiply(lambda.add(ONE)));
+
+ return new ECPoint.F2m(this.curve, x3, y3, withCompression);
+ }
+
+ public ECPoint negate()
+ {
+ return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
+ }
+
+ /**
+ * Sets the appropriate <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ if (((ECCurve.F2m)this.curve).isKoblitz())
+ {
+ this.multiplier = new WTauNafMultiplier();
+ }
+ else
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
index 5303ab85..58643a78 100644
--- a/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
+++ b/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
@@ -379,7 +379,19 @@ public class PGPSecretKey
{
return pub.isMasterKey();
}
-
+
+ /**
+ * Detect if the Secret Key's Private Key is empty or not
+ *
+ * @return boolean whether or not the private key is empty
+ */
+ public boolean isPrivateKeyEmpty()
+ {
+ byte[] secKeyData = secret.getSecretKeyData();
+
+ return (secKeyData == null || secKeyData.length < 1);
+ }
+
/**
* return the algorithm the key is encrypted with.
*
@@ -491,9 +503,12 @@ public class PGPSecretKey
}
//
- // verify checksum
+ // verify and copy checksum
//
+ data[pos] = encData[pos];
+ data[pos + 1] = encData[pos + 1];
+
int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
int calcCs = 0;
for (int j = 0; j < data.length - 2; j++)
@@ -573,8 +588,7 @@ public class PGPSecretKey
PBESecretKeyDecryptor decryptorFactory)
throws PGPException
{
- byte[] secKeyData = secret.getSecretKeyData();
- if (secKeyData == null || secKeyData.length < 1)
+ if (isPrivateKeyEmpty())
{
return null;
}
@@ -759,8 +773,8 @@ public class PGPSecretKey
* password and the passed in algorithm.
*
* @param key the PGPSecretKey to be copied.
- * @param oldKeyDecryptor the current password for key.
- * @param newKeyEncryptor the encryptor for encrypting the secret key material.
+ * @param oldKeyDecryptor the current decryptor based on the current password for key.
+ * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key material.
*/
public static PGPSecretKey copyWithNewPassword(
PGPSecretKey key,
@@ -768,7 +782,12 @@ public class PGPSecretKey
PBESecretKeyEncryptor newKeyEncryptor)
throws PGPException
{
- byte[] rawKeyData = key.extractKeyData(oldKeyDecryptor);
+ if (key.isPrivateKeyEmpty())
+ {
+ throw new PGPException("no private key in this SecretKey - public key present only.");
+ }
+
+ byte[] rawKeyData = key.extractKeyData(oldKeyDecryptor);
int s2kUsage = key.secret.getS2KUsage();
byte[] iv = null;
S2K s2k = null;
@@ -796,13 +815,67 @@ public class PGPSecretKey
}
else
{
- keyData = newKeyEncryptor.encryptKeyData(rawKeyData, 0, rawKeyData.length);
+ if (key.secret.getPublicKeyPacket().getVersion() < 4)
+ {
+ // Version 2 or 3 - RSA Keys only
- iv = newKeyEncryptor.getCipherIV();
+ byte[] encKey = newKeyEncryptor.getKey();
+ keyData = new byte[rawKeyData.length];
- s2k = newKeyEncryptor.getS2K();
+ if (newKeyEncryptor.getS2K() != null)
+ {
+ throw new PGPException("MD5 Digest Calculator required for version 3 key encryptor.");
+ }
+
+ //
+ // process 4 numbers
+ //
+ int pos = 0;
+ for (int i = 0; i != 4; i++)
+ {
+ int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8;
- newEncAlgorithm = newKeyEncryptor.getAlgorithm();
+ keyData[pos] = rawKeyData[pos];
+ keyData[pos + 1] = rawKeyData[pos + 1];
+
+ byte[] tmp;
+ if (i == 0)
+ {
+ tmp = newKeyEncryptor.encryptKeyData(encKey, rawKeyData, pos + 2, encLen);
+ iv = newKeyEncryptor.getCipherIV();
+
+ }
+ else
+ {
+ byte[] tmpIv = new byte[iv.length];
+
+ System.arraycopy(keyData, pos - iv.length, tmpIv, 0, tmpIv.length);
+ tmp = newKeyEncryptor.encryptKeyData(encKey, tmpIv, rawKeyData, pos + 2, encLen);
+ }
+
+ System.arraycopy(tmp, 0, keyData, pos + 2, tmp.length);
+ pos += 2 + encLen;
+ }
+
+ //
+ // copy in checksum.
+ //
+ keyData[pos] = rawKeyData[pos];
+ keyData[pos + 1] = rawKeyData[pos + 1];
+
+ s2k = newKeyEncryptor.getS2K();
+ newEncAlgorithm = newKeyEncryptor.getAlgorithm();
+ }
+ else
+ {
+ keyData = newKeyEncryptor.encryptKeyData(rawKeyData, 0, rawKeyData.length);
+
+ iv = newKeyEncryptor.getCipherIV();
+
+ s2k = newKeyEncryptor.getS2K();
+
+ newEncAlgorithm = newKeyEncryptor.getAlgorithm();
+ }
}
SecretKeyPacket secret;
@@ -819,6 +892,7 @@ public class PGPSecretKey
return new PGPSecretKey(secret, key.pub);
}
+
/**
* Return a copy of the passed in secret key, encrypted using a new
* password and the passed in algorithm.
diff --git a/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java b/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java
index fd66178f..2e30e737 100644
--- a/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java
+++ b/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java
@@ -20,6 +20,8 @@ import org.bouncycastle.bcpg.SecretKeyPacket;
import org.bouncycastle.bcpg.SecretSubkeyPacket;
import org.bouncycastle.bcpg.TrustPacket;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
/**
@@ -312,6 +314,7 @@ public class PGPSecretKeyRing
* @param newEncAlgorithm the algorithm to be used for the encryption.
* @param rand source of randomness.
* @param provider name of the provider to use
+ * @deprecated use version taking PBESecretKeyEncryptor/PBESecretKeyDecryptor
*/
public static PGPSecretKeyRing copyWithNewPassword(
PGPSecretKeyRing ring,
@@ -335,6 +338,7 @@ public class PGPSecretKeyRing
* @param newEncAlgorithm the algorithm to be used for the encryption.
* @param rand source of randomness.
* @param provider provider to use
+ * @deprecated use version taking PBESecretKeyEncryptor/PBESecretKeyDecryptor
*/
public static PGPSecretKeyRing copyWithNewPassword(
PGPSecretKeyRing ring,
@@ -356,6 +360,40 @@ public class PGPSecretKeyRing
}
/**
+ * Return a copy of the passed in secret key ring, with the private keys (where present) associated with the master key and sub keys
+ * are encrypted using a new password and the passed in algorithm.
+ *
+ * @param ring the PGPSecretKeyRing to be copied.
+ * @param oldKeyDecryptor the current decryptor based on the current password for key.
+ * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key material.
+ * @return the updated key ring.
+ */
+ public static PGPSecretKeyRing copyWithNewPassword(
+ PGPSecretKeyRing ring,
+ PBESecretKeyDecryptor oldKeyDecryptor,
+ PBESecretKeyEncryptor newKeyEncryptor)
+ throws PGPException
+ {
+ List newKeys = new ArrayList(ring.keys.size());
+
+ for (Iterator keys = ring.getSecretKeys(); keys.hasNext();)
+ {
+ PGPSecretKey key = (PGPSecretKey)keys.next();
+
+ if (key.isPrivateKeyEmpty())
+ {
+ newKeys.add(key);
+ }
+ else
+ {
+ newKeys.add(PGPSecretKey.copyWithNewPassword(key, oldKeyDecryptor, newKeyEncryptor));
+ }
+ }
+
+ return new PGPSecretKeyRing(newKeys, ring.extraPubKeys);
+ }
+
+ /**
* Returns a new key ring with the secret key passed in either added or
* replacing an existing one with the same key ID.
*
diff --git a/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyEncryptor.java b/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyEncryptor.java
index 905e53de..a0d44570 100644
--- a/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyEncryptor.java
+++ b/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyEncryptor.java
@@ -2,6 +2,7 @@ package org.bouncycastle.openpgp.operator;
import java.security.SecureRandom;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.S2K;
import org.bouncycastle.openpgp.PGPException;
@@ -43,7 +44,7 @@ public abstract class PBESecretKeyEncryptor
public byte[] getKey()
throws PGPException
{
- if (s2k == null)
+ if (s2k == null && s2kDigestCalculator.getAlgorithm() != HashAlgorithmTags.MD5)
{
byte[] iv = new byte[8];
@@ -69,5 +70,17 @@ public abstract class PBESecretKeyEncryptor
public abstract byte[] encryptKeyData(byte[] key, byte[] keyData, int keyOff, int keyLen)
throws PGPException;
+ /**
+ * Encrypt the passed in keyData using the key and the iv provided.
+ * <p>
+ * This method is only used for processing version 3 keys.
+ * </p>
+ */
+ public byte[] encryptKeyData(byte[] key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+ throws PGPException
+ {
+ throw new PGPException("encryption of version 3 keys not supported.");
+ }
+
public abstract byte[] getCipherIV();
}
diff --git a/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyEncryptorBuilder.java b/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyEncryptorBuilder.java
index 7e475e0a..2258484e 100644
--- a/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyEncryptorBuilder.java
+++ b/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyEncryptorBuilder.java
@@ -32,6 +32,13 @@ public class BcPBESecretKeyEncryptorBuilder
this(encAlgorithm, new SHA1PGPDigestCalculator(), s2kCount);
}
+ /**
+ * Create a builder which will make encryptors using the passed in digest calculator. If a MD5 calculator is
+ * passed in the builder will assume the encryptors are for use with version 3 keys.
+ *
+ * @param encAlgorithm encryption algorithm to use.
+ * @param s2kDigestCalculator digest calculator to use.
+ */
public BcPBESecretKeyEncryptorBuilder(int encAlgorithm, PGPDigestCalculator s2kDigestCalculator)
{
this(encAlgorithm, s2kDigestCalculator, 0x60);
@@ -85,18 +92,31 @@ public class BcPBESecretKeyEncryptorBuilder
public byte[] encryptKeyData(byte[] key, byte[] keyData, int keyOff, int keyLen)
throws PGPException
{
+ return encryptKeyData(key, null, keyData, keyOff, keyLen);
+ }
+
+ public byte[] encryptKeyData(byte[] key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+ throws PGPException
+ {
try
{
- if (this.random == null)
- {
- this.random = new SecureRandom();
- }
-
BlockCipher engine = BcImplProvider.createBlockCipher(this.encAlgorithm);
- iv = new byte[engine.getBlockSize()];
+ if (iv != null)
+ { // to deal with V3 key encryption
+ this.iv = iv;
+ }
+ else
+ {
+ if (this.random == null)
+ {
+ this.random = new SecureRandom();
+ }
+
+ this.iv = iv = new byte[engine.getBlockSize()];
- this.random.nextBytes(iv);
+ this.random.nextBytes(iv);
+ }
BufferedBlockCipher c = BcUtil.createSymmetricKeyWrapper(true, engine, key, iv);
diff --git a/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyEncryptorBuilder.java b/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyEncryptorBuilder.java
index 4d7c94d7..0890ddb9 100644
--- a/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyEncryptorBuilder.java
+++ b/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyEncryptorBuilder.java
@@ -1,5 +1,6 @@
package org.bouncycastle.openpgp.operator.jcajce;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Provider;
import java.security.SecureRandom;
@@ -7,6 +8,7 @@ import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.jcajce.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.NamedJcaJceHelper;
@@ -29,7 +31,7 @@ public class JcePBESecretKeyEncryptorBuilder
}
/**
- * Create an SecretKeyEncryptorBuilder with the S2K count different to the default of 0x60.
+ * Create a SecretKeyEncryptorBuilder with the S2K count different to the default of 0x60.
*
* @param encAlgorithm encryption algorithm to use.
* @param s2kCount iteration count to use for S2K function.
@@ -39,6 +41,13 @@ public class JcePBESecretKeyEncryptorBuilder
this(encAlgorithm, new SHA1PGPDigestCalculator(), s2kCount);
}
+ /**
+ * Create a builder which will make encryptors using the passed in digest calculator. If a MD5 calculator is
+ * passed in the builder will assume the encryptors are for use with version 3 keys.
+ *
+ * @param encAlgorithm encryption algorithm to use.
+ * @param s2kDigestCalculator digest calculator to use.
+ */
public JcePBESecretKeyEncryptorBuilder(int encAlgorithm, PGPDigestCalculator s2kDigestCalculator)
{
this(encAlgorithm, s2kDigestCalculator, 0x60);
@@ -131,6 +140,37 @@ public class JcePBESecretKeyEncryptorBuilder
}
}
+ public byte[] encryptKeyData(byte[] key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+ throws PGPException
+ {
+ try
+ {
+ c = helper.createCipher(PGPUtil.getSymmetricCipherName(this.encAlgorithm) + "/CFB/NoPadding");
+
+ c.init(Cipher.ENCRYPT_MODE, PGPUtil.makeSymmetricKey(this.encAlgorithm, key), new IvParameterSpec(iv));
+
+ this.iv = iv;
+
+ return c.doFinal(keyData, keyOff, keyLen);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new PGPException("illegal block size: " + e.getMessage(), e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new PGPException("bad padding: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PGPException("invalid key: " + e.getMessage(), e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new PGPException("invalid iv: " + e.getMessage(), e);
+ }
+ }
+
public byte[] getCipherIV()
{
return iv;
diff --git a/src/main/java/org/bouncycastle/util/Arrays.java b/src/main/java/org/bouncycastle/util/Arrays.java
index bbabc8b8..6c825cd2 100644
--- a/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/src/main/java/org/bouncycastle/util/Arrays.java
@@ -716,13 +716,21 @@ public final class Arrays
return rv;
}
+ else if (d == null)
+ {
+ return concatenate(a, b, c);
+ }
+ else if (c == null)
+ {
+ return concatenate(a, b, d);
+ }
else if (b == null)
{
return concatenate(a, c, d);
}
else
{
- return concatenate(a, b, d);
+ return concatenate(b, c, d);
}
}
}
diff --git a/src/main/java/org/bouncycastle/util/Memoable.java b/src/main/java/org/bouncycastle/util/Memoable.java
new file mode 100644
index 00000000..0be91711
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/Memoable.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.util;
+
+public interface Memoable
+{
+ /**
+ * Produce a copy of this object with its configuration and in its current state.
+ * <p/>
+ * The returned object may be used simply to store the state, or may be used as a similar object
+ * starting from the copied state.
+ */
+ public Memoable copy();
+
+ /**
+ * Restore a copied object state into this object.
+ * <p/>
+ * Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.
+ *
+ * @param other an object originally {@link #copy() copied} from an object of the same type as this instance.
+ * @throws ClassCastException if the provided object is not of the correct type.
+ * @throws MemoableResetException if the <b>other</b> parameter is in some other way invalid.
+ */
+ public void reset(Memoable other);
+}
diff --git a/src/main/java/org/bouncycastle/util/MemoableResetException.java b/src/main/java/org/bouncycastle/util/MemoableResetException.java
new file mode 100644
index 00000000..6552bd49
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/MemoableResetException.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.util;
+
+/**
+ * Exception to be thrown on a failure to reset an object implementing Memoable.
+ * <p>
+ * The exception extends ClassCastException to enable users to have a single handling case,
+ * only introducing specific handling of this one if required.
+ * </p>
+ */
+public class MemoableResetException
+ extends ClassCastException
+{
+ /**
+ * Basic Constructor.
+ *
+ * @param msg message to be associated with this exception.
+ */
+ public MemoableResetException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/util/encoders/Base64.java b/src/main/java/org/bouncycastle/util/encoders/Base64.java
index 9b7d0e43..83806295 100644
--- a/src/main/java/org/bouncycastle/util/encoders/Base64.java
+++ b/src/main/java/org/bouncycastle/util/encoders/Base64.java
@@ -1,151 +1,151 @@
-package org.bouncycastle.util.encoders;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.bouncycastle.util.Strings;
-
-public class Base64
-{
- private static final Encoder encoder = new Base64Encoder();
-
- public static String toBase64String(
- byte[] data)
- {
- return toBase64String(data, 0, data.length);
- }
-
- public static String toBase64String(
- byte[] data,
- int off,
- int length)
- {
- byte[] encoded = encode(data, off, length);
- return Strings.fromByteArray(encoded);
- }
-
- /**
- * encode the input data producing a base 64 encoded byte array.
- *
- * @return a byte array containing the base 64 encoded data.
- */
- public static byte[] encode(
- byte[] data)
- {
- return encode(data, 0, data.length);
- }
-
- /**
- * encode the input data producing a base 64 encoded byte array.
- *
- * @return a byte array containing the base 64 encoded data.
- */
- public static byte[] encode(
- byte[] data,
- int off,
- int length)
- {
- int len = (length + 2) / 3 * 4;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.encode(data, off, length, bOut);
- }
- catch (Exception e)
- {
- throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * Encode the byte data to base 64 writing it to the given output stream.
- *
- * @return the number of bytes produced.
- */
- public static int encode(
- byte[] data,
- OutputStream out)
- throws IOException
- {
- return encoder.encode(data, 0, data.length, out);
- }
-
- /**
- * Encode the byte data to base 64 writing it to the given output stream.
- *
- * @return the number of bytes produced.
- */
- public static int encode(
- byte[] data,
- int off,
- int length,
- OutputStream out)
- throws IOException
- {
- return encoder.encode(data, off, length, out);
- }
-
- /**
- * decode the base 64 encoded input data. It is assumed the input data is valid.
- *
- * @return a byte array representing the decoded data.
- */
- public static byte[] decode(
- byte[] data)
- {
- int len = data.length / 4 * 3;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.decode(data, 0, data.length, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the base 64 encoded String data - whitespace will be ignored.
- *
- * @return a byte array representing the decoded data.
- */
- public static byte[] decode(
- String data)
- {
- int len = data.length() / 4 * 3;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.decode(data, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the base 64 encoded String data writing it to the given output stream,
- * whitespace characters will be ignored.
- *
- * @return the number of bytes produced.
- */
- public static int decode(
- String data,
- OutputStream out)
- throws IOException
- {
- return encoder.decode(data, out);
- }
-}
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.util.Strings;
+
+public class Base64
+{
+ private static final Encoder encoder = new Base64Encoder();
+
+ public static String toBase64String(
+ byte[] data)
+ {
+ return toBase64String(data, 0, data.length);
+ }
+
+ public static String toBase64String(
+ byte[] data,
+ int off,
+ int length)
+ {
+ byte[] encoded = encode(data, off, length);
+ return Strings.fromByteArray(encoded);
+ }
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ int len = (length + 2) / 3 * 4;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.encode(data, off, length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the base 64 encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ int len = data.length / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ int len = data.length() / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/src/main/java/org/bouncycastle/util/encoders/Hex.java b/src/main/java/org/bouncycastle/util/encoders/Hex.java
index 6a1c0f8e..d49f1ef4 100644
--- a/src/main/java/org/bouncycastle/util/encoders/Hex.java
+++ b/src/main/java/org/bouncycastle/util/encoders/Hex.java
@@ -1,148 +1,148 @@
-package org.bouncycastle.util.encoders;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.bouncycastle.util.Strings;
-
-public class Hex
-{
- private static final Encoder encoder = new HexEncoder();
-
- public static String toHexString(
- byte[] data)
- {
- return toHexString(data, 0, data.length);
- }
-
- public static String toHexString(
- byte[] data,
- int off,
- int length)
- {
- byte[] encoded = encode(data, off, length);
- return Strings.fromByteArray(encoded);
- }
-
- /**
- * encode the input data producing a Hex encoded byte array.
- *
- * @return a byte array containing the Hex encoded data.
- */
- public static byte[] encode(
- byte[] data)
- {
- return encode(data, 0, data.length);
- }
-
- /**
- * encode the input data producing a Hex encoded byte array.
- *
- * @return a byte array containing the Hex encoded data.
- */
- public static byte[] encode(
- byte[] data,
- int off,
- int length)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- try
- {
- encoder.encode(data, off, length, bOut);
- }
- catch (Exception e)
- {
- throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * Hex encode the byte data writing it to the given output stream.
- *
- * @return the number of bytes produced.
- */
- public static int encode(
- byte[] data,
- OutputStream out)
- throws IOException
- {
- return encoder.encode(data, 0, data.length, out);
- }
-
- /**
- * Hex encode the byte data writing it to the given output stream.
- *
- * @return the number of bytes produced.
- */
- public static int encode(
- byte[] data,
- int off,
- int length,
- OutputStream out)
- throws IOException
- {
- return encoder.encode(data, off, length, out);
- }
-
- /**
- * decode the Hex encoded input data. It is assumed the input data is valid.
- *
- * @return a byte array representing the decoded data.
- */
- public static byte[] decode(
- byte[] data)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- try
- {
- encoder.decode(data, 0, data.length, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("exception decoding Hex data: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the Hex encoded String data - whitespace will be ignored.
- *
- * @return a byte array representing the decoded data.
- */
- public static byte[] decode(
- String data)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- try
- {
- encoder.decode(data, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the Hex encoded String data writing it to the given output stream,
- * whitespace characters will be ignored.
- *
- * @return the number of bytes produced.
- */
- public static int decode(
- String data,
- OutputStream out)
- throws IOException
- {
- return encoder.decode(data, out);
- }
-}
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.util.Strings;
+
+public class Hex
+{
+ private static final Encoder encoder = new HexEncoder();
+
+ public static String toHexString(
+ byte[] data)
+ {
+ return toHexString(data, 0, data.length);
+ }
+
+ public static String toHexString(
+ byte[] data,
+ int off,
+ int length)
+ {
+ byte[] encoded = encode(data, off, length);
+ return Strings.fromByteArray(encoded);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.encode(data, off, length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the Hex encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding Hex data: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (Exception e)
+ {
+ throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/src/test/java/org/bouncycastle/cert/ocsp/test/OCSPTest.java b/src/test/java/org/bouncycastle/cert/ocsp/test/OCSPTest.java
index 06a8ef29..5df298ae 100644
--- a/src/test/java/org/bouncycastle/cert/ocsp/test/OCSPTest.java
+++ b/src/test/java/org/bouncycastle/cert/ocsp/test/OCSPTest.java
@@ -1,5 +1,6 @@
package org.bouncycastle.cert.ocsp.test;
+import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.Security;
@@ -931,6 +932,35 @@ public class OCSPTest
testRSA();
testIrregularVersionReq();
testInvalidResp();
+
+ //
+ // Empty data test
+ //
+ try
+ {
+ response = new OCSPResp(new byte[0]);
+ fail("no exception thrown");
+ }
+ catch (IOException e)
+ {
+ if (!e.getMessage().equals("malformed response: no response data found"))
+ {
+ fail("wrong exception");
+ }
+ }
+
+ try
+ {
+ req = new OCSPReq(new byte[0]);
+ fail("no exception thrown");
+ }
+ catch (IOException e)
+ {
+ if (!e.getMessage().equals("malformed request: no request data found"))
+ {
+ fail("wrong exception");
+ }
+ }
}
public static void main(
diff --git a/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java b/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java
new file mode 100644
index 00000000..4c0504f8
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.crypto.prng.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testCrypto()
+ {
+ org.bouncycastle.util.test.Test[] tests = RegressionTest.tests;
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Lightweight Crypto PRNG Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java
new file mode 100644
index 00000000..ca555c18
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java
@@ -0,0 +1,513 @@
+package org.bouncycastle.crypto.prng.test;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+import org.bouncycastle.crypto.params.DESedeParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * CTR DRBG Test
+ */
+public class CTRDRBGTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "CTRDRBGTest";
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new CTRDRBGTest());
+ }
+
+ private DRBGTestVector[] createTestVectorData()
+ {
+ return new DRBGTestVector[]
+ {
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ false,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "ABC88224514D0316EA3D48AEE3C9A2B4",
+ "D3D3F372E43E7ABDC4FA293743EED076"
+ }
+ ),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ false,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "D4564EE072ACA5BD279536E14F94CB12",
+ "1CCD9AFEF15A9679BA75E35225585DEA"
+ }
+ )
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ false,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "760BED7D92B083B10AF31CF0656081EB",
+ "FD1AC41482384D823CF3FD6F0E6C88B3"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ false,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "7A4C1D7ADC8A67FDB50100ED23583A2C",
+ "43044D311C0E07541CA5C8B0916976B2"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ true,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "8FB78ABCA75C9F284E974E36141866BC",
+ "9D9745FF31C42A4488CBB771B13B5D86"
+ }
+ ),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ true,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "0E389920A09B485AA4ABD0CA7E60D89C",
+ "F4478EC6659A0D3577625B0C73A211DD"
+ }
+ )
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ true,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "64983055D014550B39DE699E43130B64",
+ "035FDDA8582A2214EC722C410A8D95D3"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"),
+ new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ true,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "A29C1A8C42FBC562D7D1DBA7DC541FFE",
+ "0BDA66B049429061C013E4228C2F44C6"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "8CF59C8CF6888B96EB1C1E3E79D82387AF08A9E5FF75E23F1FBCD4559B6B997E",
+ "69CDEF912C692D61B1DA4C05146B52EB7B8849BD87937835328254EC25A9180E"
+ }
+ ),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "E8C74A4B7BFFB53BEB80E78CA86BB6DF70E2032AEB473E0DD54D2339CEFCE9D0",
+ "26B3F823B4DBAFC23B141375E10B3AEB7A0B5DEF1C7D760B6F827D01ECD17AC7"
+ }
+ )
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "18FDEFBDC43D7A36D5D6D862205765D1D701C9F237007030DF1B8E70EE4EEE29",
+ "9888F1D38BB1CCE31B363AA1BD9B39616876C30DEE1FF0B7BD8C4C441715C833"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "BFF4B85D68C84529F24F69F9ACF1756E29BA648DDEB825C225FA32BA490EF4A9",
+ "9BD2635137A52AF7D0FCBEFEFB97EA93A0F4C438BD98956C0DACB04F15EE25B3"
+ }
+ ),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "4573AC8BBB33D7CC4DBEF3EEDF6EAE748B536C3A1082CEE4948CDB51C83A7F9C",
+ "99C628CDD87BD8C2F1FE443AA7F761DA16886436326323354DA6311FFF5BC678"
+ }
+ )
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
+ new DRBGTestVector(
+ new AESFastEngine(), 128,
+ new Bit256EntropyProvider().get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new String[]
+ {
+ "F324104E2FA14F79D8AA60DF06B93B3BC157324958F0A7EE1E193677A70E0250",
+ "78F4C840134F40DC001BFAD3A90B5EF4DEBDBFAC3CFDF0CD69A89DC4FD34713F"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
+ new DRBGTestVector(
+ new AESFastEngine(), 192,
+ new Bit320EntropyProvider().get(320),
+ false,
+ "202122232425262728292A2B",
+ 192,
+ new String[]
+ {
+ "E231244B3235B085C81604424357E85201E3828B5C45568679A5555F867AAC8C",
+ "DDD0F7BCCADADAA31A67652259CE569A271DD85CF66C3D6A7E9FAED61F38D219"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
+ new DRBGTestVector(
+ new AESFastEngine(), 192,
+ new Bit320EntropyProvider().get(320),
+ true,
+ "202122232425262728292A2B",
+ 192,
+ new String[]
+ {
+ "F780D4A2C25CF8EE7407D948EC0B724A4235D8B20E65081392755CA7912AD7C0",
+ "BA14617F915BA964CB79276BDADC840C14B631BBD1A59097054FA6DFF863B238"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
+ new DRBGTestVector(
+ new AESFastEngine(), 256,
+ new Bit384EntropyProvider().get(384),
+ false,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new String[]
+ {
+ "47111E146562E9AA2FB2A1B095D37A8165AF8FC7CA611D632BE7D4C145C83900",
+ "98A28E3B1BA363C9DAF0F6887A1CF52B833D3354D77A7C10837DD63DD2E645F8"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
+ new DRBGTestVector(
+ new AESFastEngine(), 256,
+ new Bit384EntropyProvider().get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new String[]
+ {
+ "71BB3F9C9CEAF4E6C92A83EB4C7225010EE150AC75E23F5F77AD5073EF24D88A",
+ "386DEBBBF091BBF0502957B0329938FB836B82E594A2F5FDD5EB28D4E35528F4"
+ }
+ )
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
+ new DRBGTestVector(
+ new AESFastEngine(), 256,
+ new Bit384EntropyProvider().get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new String[]
+ {
+ "1A2E3FEE9056E98D375525FDC2B63B95B47CE51FCF594D804BD5A17F2E01139B",
+ "601F95384F0D85946301D1EACE8F645A825CE38F1E2565B0C0C439448E9CA8AC"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"),
+ new DRBGTestVector(
+ new AESFastEngine(), 256,
+ new Bit384EntropyProvider().get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new String[]
+ {
+ "EAE6BCE781807E524D26605EA198077932D01EEB445B9AC6C5D99C101D29F46E",
+ "738E99C95AF59519AAD37FF3D5180986ADEBAB6E95836725097E50A8D1D0BD28"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
+ .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF")
+ };
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ DRBGTestVector[] tests = createTestVectorData();
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ DRBGTestVector tv = tests[i];
+
+ byte[] nonce = tv.nonce();
+ byte[] personalisationString = tv.personalizationString();
+
+ SP80090DRBG d = new CTRSP800DRBG(tv.getCipher(), tv.keySizeInBits(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
+
+ byte[] output = new byte[tv.expectedValue(0).length];
+
+ d.generate(output, tv.additionalInput(0), tv.predictionResistance());
+
+ byte[] expected = tv.expectedValue(0);
+
+ if (!areEqual(expected, output))
+ {
+ fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output)));
+ }
+
+ output = new byte[tv.expectedValue(0).length];
+
+ d.generate(output, tv.additionalInput(1), tv.predictionResistance());
+
+ expected = tv.expectedValue(1);
+ if (!areEqual(expected, output))
+ {
+ fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
+ }
+ }
+
+ // DESede/TDEA key parity test
+ DRBGTestVector tv = tests[0];
+
+ SP80090DRBG drbg = new CTRSP800DRBG(new KeyParityCipher(tv.getCipher()), tv.keySizeInBits(), tv.securityStrength(), tv.entropySource(), tv.personalizationString(), tv.nonce());
+
+ byte[] output = new byte[tv.expectedValue(0).length];
+
+ drbg.generate(output, tv.additionalInput(0), tv.predictionResistance());
+
+ // Exception tests
+ SP80090DRBG d;
+ try
+ {
+ d = new CTRSP800DRBG(new AESEngine(), 256, 256, new Bit232EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new DESedeEngine(), 256, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new DESedeEngine(), 168, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new AESEngine(), 192, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+ }
+
+ private class Bit232EntropyProvider
+ extends TestEntropySourceProvider
+ {
+ Bit232EntropyProvider()
+ {
+ super(Hex.decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C" +
+ "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"), true);
+ }
+ }
+
+ private class Bit256EntropyProvider
+ extends TestEntropySourceProvider
+ {
+ Bit256EntropyProvider()
+ {
+ super(Hex.decode(
+ "0001020304050607"+
+ "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"+
+ "8081828384858687"+
+ "88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"+
+ "C0C1C2C3C4C5C6C7"+
+ "C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"), true);
+ }
+ }
+
+ private class Bit320EntropyProvider
+ extends TestEntropySourceProvider
+ {
+ Bit320EntropyProvider()
+ {
+ super(Hex.decode(
+ "000102030405060708090A0B0C0D0E0F"+
+ "101112131415161718191A1B1C1D1E1F2021222324252627"+
+ "808182838485868788898A8B8C8D8E8F"+
+ "909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7"+
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
+ "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7"), true);
+ }
+ }
+
+ private class Bit384EntropyProvider
+ extends TestEntropySourceProvider
+ {
+ Bit384EntropyProvider()
+ {
+ super(Hex.decode(
+ "000102030405060708090A0B0C0D0E0F1011121314151617" +
+ "18191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F" +
+ "808182838485868788898A8B8C8D8E8F9091929394959697" +
+ "98999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7" +
+ "D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"), true);
+ }
+ }
+
+ private class KeyParityCipher
+ implements BlockCipher
+ {
+ private BlockCipher cipher;
+
+ KeyParityCipher(BlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ byte[] k = Arrays.clone(((KeyParameter)params).getKey());
+
+ DESedeParameters.setOddParity(k);
+
+ if (!Arrays.areEqual(((KeyParameter)params).getKey(), k))
+ {
+ fail("key not odd parity");
+ }
+
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return cipher.processBlock(in, inOff, out, outOff);
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ }
+ }
+
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java b/src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java
index 482db87b..dd6801c5 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java
index 9161e6e5..59ae3346 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java
@@ -1,15 +1,16 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
+import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.prng.DualECSP800DRBG;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
+import org.bouncycastle.crypto.prng.drbg.DualECSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
/**
- * Dual EC SP800-90 DRBG
+ * Dual EC SP800-90 DRBG test
*/
public class DualECDRBGTest
extends SimpleTest
@@ -272,7 +273,7 @@ public class DualECDRBGTest
byte[] nonce = tv.nonce();
byte[] personalisationString = tv.personalizationString();
- SP80090DRBG d = new DualECSP800DRBG(tv.getDigest(), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
+ SP80090DRBG d = new DualECSP800DRBG(tv.getDigest(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
byte[] output = new byte[tv.expectedValue(0).length];
@@ -295,6 +296,48 @@ public class DualECDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(1 << (13 - 1) + 1), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new DualECSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by digest"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA256EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java
index e98d770c..add77d5a 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java
@@ -1,12 +1,12 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.macs.HMac;
-import org.bouncycastle.crypto.prng.HMacSP800DRBG;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
+import org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -388,7 +388,7 @@ public class HMacDRBGTest
byte[] nonce = tv.nonce();
byte[] personalisationString = tv.personalizationString();
- SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
+ SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
byte[] output = new byte[tv.expectedValue(0).length];
@@ -411,6 +411,22 @@ public class HMacDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new HMacSP800DRBG(new HMac(new SHA256Digest()), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA1EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java
index 06304d72..ee632033 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java
@@ -1,11 +1,11 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.prng.HashSP800DRBG;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
+import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG;
+import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -348,7 +348,7 @@ public class HashDRBGTest
byte[] nonce = tv.nonce();
byte[] personalisationString = tv.personalizationString();
- SP80090DRBG d = new HashSP800DRBG(tv.getDigest(), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
+ SP80090DRBG d = new HashSP800DRBG(tv.getDigest(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
byte[] output = new byte[tv.expectedValue(0).length];
@@ -371,6 +371,35 @@ public class HashDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new HashSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new HashSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by the derivation function"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA1EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java
index e2f1e79c..d1f6f435 100644
--- a/src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.random.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.util.test.Test;
import org.bouncycastle.util.test.TestResult;
@@ -6,6 +6,10 @@ import org.bouncycastle.util.test.TestResult;
public class RegressionTest
{
public static Test[] tests = {
+ new CTRDRBGTest(),
+ new DualECDRBGTest(),
+ new HashDRBGTest(),
+ new HMacDRBGTest(),
new SP800RandomTest()
};
diff --git a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
index b18f30b0..a164f8fc 100644
--- a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.random.test;
+package org.bouncycastle.crypto.prng.test;
import java.security.SecureRandom;
@@ -6,9 +6,7 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.macs.HMac;
-import org.bouncycastle.crypto.random.SP800SecureRandomBuilder;
-import org.bouncycastle.crypto.test.DRBGTestVector;
-import org.bouncycastle.crypto.test.TestEntropySourceProvider;
+import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -220,6 +218,22 @@ public class SP800RandomTest
);
doCTRTest(tv);
+
+ tv = new DRBGTestVector(
+ new DESedeEngine(), 168,
+ new Bit232EntropyProvider().get(232),
+ true,
+ "20212223242526",
+ 112,
+ new String[]
+ {
+ "64983055D014550B39DE699E43130B64",
+ "035FDDA8582A2214EC722C410A8D95D3"
+ }
+ )
+ .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C");
+
+ doCTRTest(tv);
}
private void doCTRTest(DRBGTestVector tv)
diff --git a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java b/src/test/java/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java
index 08576977..64e75958 100644
--- a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.crypto.prng.EntropySourceProvider;
@@ -36,6 +36,11 @@ public class TestEntropySourceProvider
return rv;
}
+
+ public int entropySize()
+ {
+ return bitsRequired;
+ }
};
}
}
diff --git a/src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java b/src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java
deleted file mode 100644
index 31a98e08..00000000
--- a/src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package org.bouncycastle.crypto.test;
-
-import org.bouncycastle.crypto.engines.AESFastEngine;
-import org.bouncycastle.crypto.engines.DESedeEngine;
-import org.bouncycastle.crypto.prng.CTRSP800DRBG;
-import org.bouncycastle.crypto.prng.SP80090DRBG;
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.SimpleTest;
-
-/**
- * CTR DRBG Test
- */
-public class CTRDRBGTest
- extends SimpleTest
-{
- public String getName()
- {
- return "CTRDRBGTest";
- }
-
- public static void main(String[] args)
- {
- runTest(new CTRDRBGTest());
- }
-
- private DRBGTestVector[] createTestVectorData()
- {
- return new DRBGTestVector[]
- {
- new DRBGTestVector(
- new DESedeEngine(), 168,
- new Bit232EntropyProvider().get(232),
- false,
- "20212223242526",
- 112,
- new String[]
- {
- "ABC88224514D0316EA3D48AEE3C9A2B4",
- "D3D3F372E43E7ABDC4FA293743EED076"
- }
- ),
- new DRBGTestVector(
- new DESedeEngine(), 168,
- new Bit232EntropyProvider().get(232),
- false,
- "20212223242526",
- 112,
- new String[]
- {
- "D4564EE072ACA5BD279536E14F94CB12",
- "1CCD9AFEF15A9679BA75E35225585DEA"
- }
- )
- .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
- .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
- new DRBGTestVector(
- new DESedeEngine(), 168,
- new Bit232EntropyProvider().get(232),
- false,
- "20212223242526",
- 112,
- new String[]
- {
- "ABC88224514D0316EA3D48AEE3C9A2B4",
- "D3D3F372E43E7ABDC4FA293743EED076"
- }
- ),
- new DRBGTestVector(
- new DESedeEngine(), 168,
- new Bit232EntropyProvider().get(232),
- false,
- "20212223242526",
- 112,
- new String[]
- {
- "760BED7D92B083B10AF31CF0656081EB",
- "FD1AC41482384D823CF3FD6F0E6C88B3"
- }
- )
- .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"),
- new DRBGTestVector(
- new AESFastEngine(), 192,
- new Bit320EntropyProvider().get(320),
- false,
- "202122232425262728292A2B",
- 192,
- new String[]
- {
- "E231244B3235B085C81604424357E85201E3828B5C45568679A5555F867AAC8C",
- "DDD0F7BCCADADAA31A67652259CE569A271DD85CF66C3D6A7E9FAED61F38D219"
- }
- )
- .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
- new DRBGTestVector(
- new AESFastEngine(), 256,
- new Bit384EntropyProvider().get(384),
- false,
- "202122232425262728292A2B2C2D2E2F",
- 256,
- new String[]
- {
- "47111E146562E9AA2FB2A1B095D37A8165AF8FC7CA611D632BE7D4C145C83900",
- "98A28E3B1BA363C9DAF0F6887A1CF52B833D3354D77A7C10837DD63DD2E645F8"
- }
- )
- .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
- .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
- .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF")
- };
- }
-
- public void performTest()
- throws Exception
- {
- DRBGTestVector[] tests = createTestVectorData();
-
- for (int i = 0; i != tests.length; i++)
- {
- DRBGTestVector tv = tests[i];
-
- byte[] nonce = tv.nonce();
- byte[] personalisationString = tv.personalizationString();
-
- SP80090DRBG d = new CTRSP800DRBG(tv.getCipher(), tv.keySizeInBits(), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
-
- byte[] output = new byte[tv.expectedValue(0).length];
-
- d.generate(output, tv.additionalInput(0), tv.predictionResistance());
-
- byte[] expected = tv.expectedValue(0);
-
- if (!areEqual(expected, output))
- {
- fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output)));
- }
-
- output = new byte[tv.expectedValue(0).length];
-
- d.generate(output, tv.additionalInput(1), tv.predictionResistance());
-
- expected = tv.expectedValue(1);
- if (!areEqual(expected, output))
- {
- fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
- }
- }
- }
-
- private class Bit232EntropyProvider
- extends TestEntropySourceProvider
- {
- Bit232EntropyProvider()
- {
- super(Hex.decode(
- "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C" +
- "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C" +
- "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"), true);
- }
- }
-
- private class Bit320EntropyProvider
- extends TestEntropySourceProvider
- {
- Bit320EntropyProvider()
- {
- super(Hex.decode(
- "000102030405060708090A0B0C0D0E0F"+
- "101112131415161718191A1B1C1D1E1F2021222324252627"+
- "808182838485868788898A8B8C8D8E8F"+
- "909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7"+
- "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
- "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7"), true);
- }
- }
-
- private class Bit384EntropyProvider
- extends TestEntropySourceProvider
- {
- Bit384EntropyProvider()
- {
- super(Hex.decode(
- "000102030405060708090A0B0C0D0E0F1011121314151617" +
- "18191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F" +
- "808182838485868788898A8B8C8D8E8F9091929394959697" +
- "98999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
- "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7" +
- "D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"), true);
- }
- }
-}
diff --git a/src/test/java/org/bouncycastle/crypto/test/DSATest.java b/src/test/java/org/bouncycastle/crypto/test/DSATest.java
index 005ac521..02c748fa 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DSATest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/DSATest.java
@@ -1,23 +1,29 @@
package org.bouncycastle.crypto.test;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.DSAValidationParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.DSASigner;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
/**
- * Test based on FIPS 186-2, Appendix 5, an example of DSA.
+ * Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors.
*/
public class DSATest
extends SimpleTest
@@ -92,6 +98,476 @@ public class DSATest
{
fail("verification fails");
}
+
+ dsa2Test1();
+ dsa2Test2();
+ dsa2Test3();
+ dsa2Test4();
+ }
+
+ private void dsa2Test1()
+ {
+ byte[] seed = Hex.decode("ED8BEE8D1CB89229D2903CBF0E51EE7377F48698");
+
+ DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+ pGen.init(new DSAParameterGenerationParameters(1024, 160, 80, new DSATestSecureRandom(seed)));
+
+ DSAParameters params = pGen.generateParameters();
+
+ DSAValidationParameters pv = params.getValidationParameters();
+
+ if (pv.getCounter() != 5)
+ {
+ fail("counter incorrect");
+ }
+
+ if (!Arrays.areEqual(seed, pv.getSeed()))
+ {
+ fail("seed incorrect");
+ }
+
+ if (!params.getQ().equals(new BigInteger("E950511EAB424B9A19A2AEB4E159B7844C589C4F", 16)))
+ {
+ fail("Q incorrect");
+ }
+
+ if (!params.getP().equals(new BigInteger(
+ "E0A67598CD1B763B" +
+ "C98C8ABB333E5DDA0CD3AA0E5E1FB5BA8A7B4EABC10BA338" +
+ "FAE06DD4B90FDA70D7CF0CB0C638BE3341BEC0AF8A7330A3" +
+ "307DED2299A0EE606DF035177A239C34A912C202AA5F83B9" +
+ "C4A7CF0235B5316BFC6EFB9A248411258B30B839AF172440" +
+ "F32563056CB67A861158DDD90E6A894C72A5BBEF9E286C6B", 16)))
+ {
+ fail("P incorrect");
+ }
+
+ if (!params.getG().equals(new BigInteger(
+ "D29D5121B0423C27" +
+ "69AB21843E5A3240FF19CACC792264E3BB6BE4F78EDD1B15" +
+ "C4DFF7F1D905431F0AB16790E1F773B5CE01C804E509066A" +
+ "9919F5195F4ABC58189FD9FF987389CB5BEDF21B4DAB4F8B" +
+ "76A055FFE2770988FE2EC2DE11AD92219F0B351869AC24DA" +
+ "3D7BA87011A701CE8EE7BFE49486ED4527B7186CA4610A75", 16)))
+ {
+ fail("G incorrect");
+ }
+
+ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
+
+ kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), params));
+
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
+
+ if (!pub.getY().equals(new BigInteger(
+ "25282217F5730501" +
+ "DD8DBA3EDFCF349AAFFEC20921128D70FAC44110332201BB" +
+ "A3F10986140CBB97C726938060473C8EC97B4731DB004293" +
+ "B5E730363609DF9780F8D883D8C4D41DED6A2F1E1BBBDC97" +
+ "9E1B9D6D3C940301F4E978D65B19041FCF1E8B518F5C0576" +
+ "C770FE5A7A485D8329EE2914A2DE1B5DA4A6128CEAB70F79", 16)))
+ {
+ fail("Y value incorrect");
+ }
+
+ if (!priv.getX().equals(
+ new BigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16)))
+ {
+ fail("X value incorrect");
+ }
+
+ DSASigner signer = new DSASigner();
+
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075"))));
+
+ byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D");
+
+ BigInteger[] sig = signer.generateSignature(msg);
+
+ if (!sig[0].equals(new BigInteger("636155AC9A4633B4665D179F9E4117DF68601F34", 16)))
+ {
+ fail("R value incorrect");
+ }
+
+ if (!sig[1].equals(new BigInteger("6C540B02D9D4852F89DF8CFC99963204F4347704", 16)))
+ {
+ fail("S value incorrect");
+ }
+
+ signer.init(false, kp.getPublic());
+
+ if (!signer.verifySignature(msg, sig[0], sig[1]))
+ {
+ fail("signature not verified");
+ }
+
+ }
+
+ private void dsa2Test2()
+ {
+ byte[] seed = Hex.decode("5AFCC1EFFC079A9CCA6ECA86D6E3CC3B18642D9BE1CC6207C84002A9");
+
+ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA224Digest());
+
+ pGen.init(new DSAParameterGenerationParameters(2048, 224, 80, new DSATestSecureRandom(seed)));
+
+ DSAParameters params = pGen.generateParameters();
+
+ DSAValidationParameters pv = params.getValidationParameters();
+
+ if (pv.getCounter() != 21)
+ {
+ fail("counter incorrect");
+ }
+
+ if (!Arrays.areEqual(seed, pv.getSeed()))
+ {
+ fail("seed incorrect");
+ }
+
+ if (!params.getQ().equals(new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16)))
+ {
+ fail("Q incorrect");
+ }
+
+ if (!params.getP().equals(new BigInteger(
+ "C196BA05AC29E1F9C3C72D56DFFC6154" +
+ "A033F1477AC88EC37F09BE6C5BB95F51C296DD20D1A28A06" +
+ "7CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" +
+ "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE6" +
+ "19ECACC7E0B51652A8776D02A425567DED36EABD90CA33A1" +
+ "E8D988F0BBB92D02D1D20290113BB562CE1FC856EEB7CDD9" +
+ "2D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" +
+ "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E" +
+ "5320121496DC65B3930E38047294FF877831A16D5228418D" +
+ "E8AB275D7D75651CEFED65F78AFC3EA7FE4D79B35F62A040" +
+ "2A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16)))
+ {
+ fail("P incorrect");
+ }
+
+ if (!params.getG().equals(new BigInteger(
+ "A59A749A11242C58C894E9E5A91804E8"+
+ "FA0AC64B56288F8D47D51B1EDC4D65444FECA0111D78F35F"+
+ "C9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50"+
+ "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B"+
+ "6E770409494B7FEE1DBB1E4B2BC2A53D4F893D418B715959"+
+ "2E4FFFDF6969E91D770DAEBD0B5CB14C00AD68EC7DC1E574"+
+ "5EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF"+
+ "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E69"+
+ "5515B05BD412F5B8C2F4C77EE10DA48ABD53F5DD498927EE"+
+ "7B692BBBCDA2FB23A516C5B4533D73980B2A3B60E384ED20"+
+ "0AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16)))
+ {
+ fail("G incorrect");
+ }
+
+ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
+
+ kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params));
+
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
+
+ if (!pub.getY().equals(new BigInteger(
+ "70035C9A3B225B258F16741F3941FBF0" +
+ "6F3D056CD7BD864604CBB5EE9DD85304EE8E8E4ABD5E9032" +
+ "11DDF25CE149075510ACE166970AFDC7DF552B7244F342FA" +
+ "02F7A621405B754909D757F97290E1FE5036E904CF593446" +
+ "0C046D95659821E1597ED9F2B1F0E20863A6BBD0CE74DACB" +
+ "A5D8C68A90B29C2157CDEDB82EC12B81EE3068F9BF5F7F34" +
+ "6ECA41ED174CCCD7D154FA4F42F80FFE1BF46AE9D8125DEB" +
+ "5B4BA08A72BDD86596DBEDDC9550FDD650C58F5AE5133509" +
+ "A702F79A31ECB490F7A3C5581631F7C5BE4FF7F9E9F27FA3" +
+ "90E47347AD1183509FED6FCF198BA9A71AB3335B4F38BE8D" +
+ "15496A00B6DC2263E20A5F6B662320A3A1EC033AA61E3B68", 16)))
+ {
+ fail("Y value incorrect");
+ }
+
+ if (!priv.getX().equals(
+ new BigInteger("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17", 16)))
+ {
+ fail("X value incorrect");
+ }
+
+ DSASigner signer = new DSASigner();
+
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05"))));
+
+ byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
+
+ BigInteger[] sig = signer.generateSignature(msg);
+
+ if (!sig[0].equals(new BigInteger("4400138D05F9639CAF54A583CAAF25D2B76D0C3EAD752CE17DBC85FE", 16)))
+ {
+ fail("R value incorrect");
+ }
+
+ if (!sig[1].equals(new BigInteger("874D4F12CB13B61732D398445698CFA9D92381D938AA57EE2C9327B3", 16)))
+ {
+ fail("S value incorrect");
+ }
+
+ signer.init(false, kp.getPublic());
+
+ if (!signer.verifySignature(msg, sig[0], sig[1]))
+ {
+ fail("signature not verified");
+ }
+ }
+
+ private void dsa2Test3()
+ {
+ byte[] seed = Hex.decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0");
+
+ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest());
+
+ pGen.init(new DSAParameterGenerationParameters(2048, 256, 80, new DSATestSecureRandom(seed)));
+
+ DSAParameters params = pGen.generateParameters();
+
+ DSAValidationParameters pv = params.getValidationParameters();
+
+ if (pv.getCounter() != 12)
+ {
+ fail("counter incorrect");
+ }
+
+ if (!Arrays.areEqual(seed, pv.getSeed()))
+ {
+ fail("seed incorrect");
+ }
+
+ if (!params.getQ().equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16)))
+ {
+ fail("Q incorrect");
+ }
+
+ if (!params.getP().equals(new BigInteger(
+ "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+ "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+ "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+ "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+ "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+ "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+ "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+ "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+ "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+ "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+ "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16)))
+ {
+ fail("P incorrect");
+ }
+
+ if (!params.getG().equals(new BigInteger(
+ "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+ "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+ "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+ "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+ "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+ "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+ "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+ "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+ "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+ "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+ "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)))
+ {
+ fail("G incorrect");
+ }
+
+ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
+
+ kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params));
+
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
+
+ if (!pub.getY().equals(new BigInteger(
+ "2828003D7C747199143C370FDD07A286" +
+ "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+ "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+ "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+ "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+ "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+ "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+ "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+ "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+ "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+ "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16)))
+ {
+ fail("Y value incorrect");
+ }
+
+ if (!priv.getX().equals(
+ new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16)))
+ {
+ fail("X value incorrect");
+ }
+
+ DSASigner signer = new DSASigner();
+
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))));
+
+ byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
+
+ BigInteger[] sig = signer.generateSignature(msg);
+
+ if (!sig[0].equals(new BigInteger("315C875DCD4850E948B8AC42824E9483A32D5BA5ABE0681B9B9448D444F2BE3C", 16)))
+ {
+ fail("R value incorrect");
+ }
+
+ if (!sig[1].equals(new BigInteger("89718D12E54A8D9ED066E4A55F7ED5A2229CD23B9A3CEE78F83ED6AA61F6BCB9", 16)))
+ {
+ fail("S value incorrect");
+ }
+
+ signer.init(false, kp.getPublic());
+
+ if (!signer.verifySignature(msg, sig[0], sig[1]))
+ {
+ fail("signature not verified");
+ }
+ }
+
+ private void dsa2Test4()
+ {
+ byte[] seed = Hex.decode("193AFCA7C1E77B3C1ECC618C81322E47B8B8B997C9C83515C59CC446C2D9BD47");
+
+ DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest());
+
+ pGen.init(new DSAParameterGenerationParameters(3072, 256, 80, new DSATestSecureRandom(seed)));
+
+ DSAParameters params = pGen.generateParameters();
+
+ DSAValidationParameters pv = params.getValidationParameters();
+
+ if (pv.getCounter() != 20)
+ {
+ fail("counter incorrect");
+ }
+
+ if (!Arrays.areEqual(seed, pv.getSeed()))
+ {
+ fail("seed incorrect");
+ }
+
+ if (!params.getQ().equals(new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16)))
+ {
+ fail("Q incorrect");
+ }
+
+ if (!params.getP().equals(new BigInteger(
+ "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD610" +
+ "37E56258A7795A1C7AD46076982CE6BB956936C6AB4DCFE0" +
+ "5E6784586940CA544B9B2140E1EB523F009D20A7E7880E4E" +
+ "5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" +
+ "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D" +
+ "3485261CD068699B6BA58A1DDBBEF6DB51E8FE34E8A78E54" +
+ "2D7BA351C21EA8D8F1D29F5D5D15939487E27F4416B0CA63" +
+ "2C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" +
+ "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0E" +
+ "E6F29AF7F642773EBE8CD5402415A01451A840476B2FCEB0" +
+ "E388D30D4B376C37FE401C2A2C2F941DAD179C540C1C8CE0" +
+ "30D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" +
+ "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C56" +
+ "0EA878DE87C11E3D597F1FEA742D73EEC7F37BE43949EF1A" +
+ "0D15C3F3E3FC0A8335617055AC91328EC22B50FC15B941D3" +
+ "D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16)))
+ {
+ fail("P incorrect");
+ }
+
+ if (!params.getG().equals(new BigInteger(
+ "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE" +
+ "3B7ACCC54D521E37F84A4BDD5B06B0970CC2D2BBB715F7B8" +
+ "2846F9A0C393914C792E6A923E2117AB805276A975AADB52" +
+ "61D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" +
+ "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A" +
+ "60126FEB2CF05DB8A7F0F09B3397F3937F2E90B9E5B9C9B6" +
+ "EFEF642BC48351C46FB171B9BFA9EF17A961CE96C7E7A7CC" +
+ "3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" +
+ "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B6" +
+ "7299E231F8BD90B39AC3AE3BE0C6B6CACEF8289A2E2873D5" +
+ "8E51E029CAFBD55E6841489AB66B5B4B9BA6E2F784660896" +
+ "AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" +
+ "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B98856" +
+ "7A88126B914D7828E2B63A6D7ED0747EC59E0E0A23CE7D8A" +
+ "74C1D2C2A7AFB6A29799620F00E11C33787F7DED3B30E1A2" +
+ "2D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16)))
+ {
+ fail("G incorrect");
+ }
+
+ DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
+
+ kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params));
+
+ AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
+
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
+
+ if (!pub.getY().equals(new BigInteger(
+ "8B891C8692D3DE875879390F2698B26FBECCA6B075535DCE" +
+ "6B0C862577F9FA0DEF6074E7A7624121224A595896ABD4CD" +
+ "A56B2CEFB942E025D2A4282FFAA98A48CDB47E1A6FCB5CFB" +
+ "393EF35AF9DF913102BB303C2B5C36C3F8FC04ED7B8B69FE" +
+ "FE0CF3E1FC05CFA713B3435B2656E913BA8874AEA9F93600" +
+ "6AEB448BCD005D18EC3562A33D04CF25C8D3D69844343442" +
+ "FA3DB7DE618C5E2DA064573E61E6D5581BFB694A23AC87FD" +
+ "5B52D62E954E1376DB8DDB524FFC0D469DF978792EE44173" +
+ "8E5DB05A7DC43E94C11A2E7A4FBE383071FA36D2A7EC8A93" +
+ "88FE1C4F79888A99D3B6105697C2556B79BB4D7E781CEBB3" +
+ "D4866AD825A5E830846072289FDBC941FA679CA82F5F78B7" +
+ "461B2404DB883D215F4E0676CF5493950AC5591697BFEA8D" +
+ "1EE6EC016B89BA51CAFB5F9C84C989FA117375E94578F28B" +
+ "E0B34CE0545DA46266FD77F62D8F2CEE92AB77012AFEBC11" +
+ "008985A821CD2D978C7E6FE7499D1AAF8DE632C21BB48CA5" +
+ "CBF9F31098FD3FD3854C49A65D9201744AACE540354974F9", 16)))
+ {
+ fail("Y value incorrect");
+ }
+
+ if (!priv.getX().equals(
+ new BigInteger("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764", 16)))
+ {
+ fail("X value incorrect");
+ }
+
+ DSASigner signer = new DSASigner();
+
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"))));
+
+ byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
+
+ BigInteger[] sig = signer.generateSignature(msg);
+
+ if (!sig[0].equals(new BigInteger("5F184E645A38BE8FB4A6871B6503A9D12924C7ABE04B71410066C2ECA6E3BE3E", 16)))
+ {
+ fail("R value incorrect");
+ }
+
+ if (!sig[1].equals(new BigInteger("91EB0C7BA3D4B9B60B825C3D9F2CADA8A2C9D7723267B033CBCDCF8803DB9C18", 16)))
+ {
+ fail("S value incorrect");
+ }
+
+ signer.init(false, kp.getPublic());
+
+ if (!signer.verifySignature(msg, sig[0], sig[1]))
+ {
+ fail("signature not verified");
+ }
}
public static void main(
@@ -99,4 +575,28 @@ public class DSATest
{
runTest(new DSATest());
}
+
+ private class DSATestSecureRandom
+ extends FixedSecureRandom
+ {
+ private boolean first = true;
+
+ public DSATestSecureRandom(byte[] value)
+ {
+ super(value);
+ }
+
+ public void nextBytes(byte[] bytes)
+ {
+ if (first)
+ {
+ super.nextBytes(bytes);
+ first = false;
+ }
+ else
+ {
+ bytes[bytes.length - 1] = 2;
+ }
+ }
+ }
}
diff --git a/src/test/java/org/bouncycastle/crypto/test/DigestTest.java b/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
index 92cdc63f..f66f2a52 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.util.Memoable;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -65,6 +66,45 @@ public abstract class DigestTest
{
fail("failing second clone vector test", results[results.length - 1], new String(Hex.encode(resBuf)));
}
+
+ //
+ // memo test
+ //
+ Memoable m = (Memoable)digest;
+
+ digest.update(lastV, 0, lastV.length/2);
+
+ // copy the Digest
+ Memoable copy1 = m.copy();
+ Memoable copy2 = copy1.copy();
+
+ digest.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ digest.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing memo vector test", results[results.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ m.reset(copy1);
+
+ digest.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ digest.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing memo reset vector test", results[results.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ Digest md = (Digest)copy2;
+
+ md.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ md.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing memo copy vector test", results[results.length - 1], new String(Hex.encode(resBuf)));
+ }
}
private byte[] toByteArray(String input)
diff --git a/src/test/java/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java b/src/test/java/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java
new file mode 100755
index 00000000..5d0b76ca
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.crypto.test;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+import org.bouncycastle.crypto.kems.ECIESKeyEncapsulation;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * Tests for the ECIES Key Encapsulation Mechanism
+ */
+public class ECIESKeyEncapsulationTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "ECIESKeyEncapsulation";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+
+ // Set EC domain parameters and generate key pair
+ X9ECParameters spec = SECNamedCurves.getByName("secp224r1");
+ ECDomainParameters ecDomain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN());
+ ECKeyPairGenerator ecGen = new ECKeyPairGenerator();
+
+ ecGen.init(new ECKeyGenerationParameters(ecDomain, new SecureRandom()));
+
+ AsymmetricCipherKeyPair keys = ecGen.generateKeyPair();
+
+ // Set ECIES-KEM parameters
+ ECIESKeyEncapsulation kem;
+ KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest());
+ SecureRandom rnd = new SecureRandom();
+ byte[] out = new byte[57];
+ KeyParameter key1, key2;
+
+ // Test basic ECIES-KEM
+ kem = new ECIESKeyEncapsulation(kdf, rnd);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed basic test");
+ }
+
+ // Test ECIES-KEM using new cofactor mode
+ kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, false);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed cofactor test");
+ }
+
+ // Test ECIES-KEM using old cofactor mode
+ kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, false);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed old cofactor test");
+ }
+
+ // Test ECIES-KEM using single hash mode
+ kem = new ECIESKeyEncapsulation(kdf, rnd, false, false, true);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed single hash test");
+ }
+
+ // Test ECIES-KEM using new cofactor mode and single hash mode
+ kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, true);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed cofactor and single hash test");
+ }
+
+ // Test ECIES-KEM using old cofactor mode and single hash mode
+ kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, true);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed old cofactor and single hash test");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new ECIESKeyEncapsulationTest());
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/GMacTest.java b/src/test/java/org/bouncycastle/crypto/test/GMacTest.java
new file mode 100644
index 00000000..d8196f96
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/test/GMacTest.java
@@ -0,0 +1,170 @@
+package org.bouncycastle.crypto.test;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * Test vectors for AES-GMAC, extracted from <a
+ * href="http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip">NIST CAVP GCM test
+ * vectors</a>.
+ *
+ */
+public class GMacTest extends SimpleTest
+{
+ private static class TestCase
+ {
+ private byte[] key;
+ private byte[] iv;
+ private byte[] ad;
+ private byte[] tag;
+ private String name;
+
+ private TestCase(final String name, final String key, final String iv, final String ad, final String tag)
+ {
+ this.name = name;
+ this.key = Hex.decode(key);
+ this.iv = Hex.decode(iv);
+ this.ad = Hex.decode(ad);
+ this.tag = Hex.decode(tag);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public byte[] getIv()
+ {
+ return iv;
+ }
+
+ public byte[] getAd()
+ {
+ return ad;
+ }
+
+ public byte[] getTag()
+ {
+ return tag;
+ }
+ }
+
+ private static TestCase[] TEST_VECTORS = new TestCase[] {
+ // Count = 0, from each of the PTlen = 0 test vector sequences
+ new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "",
+ "250327c674aaf477aef2675748cf6971"),
+ new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "",
+ "b6e6f197168f5049aeda32dafbdaeb"),
+ new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "",
+ "89b43e9dbc1b4f597dbbc7655bb5"),
+ new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "",
+ "2e58ce7dabd107c82759c66a75"),
+ new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "",
+ "014280f944f53c681164b2ff"),
+
+ new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3",
+ "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"),
+ new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c",
+ "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"),
+
+ new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23",
+ "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc",
+ "3f4fba100eaf1f34b0baadaae9995d85"),
+ new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00",
+ "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137",
+ "2a5dc173285375dc82835876"),
+
+ new TestCase(
+ "128/1024/0/128",
+ "d0f1f4defa1e8c08b4b26d576392027c",
+ "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+ "", "7ab49b57ddf5f62c427950111c5c4f0d"),
+ new TestCase(
+ "128/1024/384/96",
+ "3cce72d37933394a8cac8a82deada8f0",
+ "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894",
+ "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1",
+ "a3a9444b21f330c3df64c8b6"), };
+
+ public void performTest()
+ {
+ for (int i = 0; i < TEST_VECTORS.length; i++)
+ {
+ TestCase testCase = TEST_VECTORS[i];
+
+ Mac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), testCase.getTag().length * 8);
+ CipherParameters key = new KeyParameter(testCase.getKey());
+ mac.init(new ParametersWithIV(key, testCase.getIv()));
+
+ testSingleByte(mac, testCase);
+ testMultibyte(mac, testCase);
+ }
+
+ // Invalid mac size
+ testInvalidMacSize(97);
+ testInvalidMacSize(136);
+ testInvalidMacSize(88);
+ testInvalidMacSize(64);
+ }
+
+ private void testInvalidMacSize(int size)
+ {
+ try
+ {
+ GMac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), size);
+ mac.init(new ParametersWithIV(null, new byte[16]));
+ fail("Expected failure for illegal mac size " + size);
+ } catch (IllegalArgumentException e)
+ {
+ }
+ }
+
+ private void testMultibyte(Mac mac, TestCase testCase)
+ {
+ mac.update(testCase.getAd(), 0, testCase.getAd().length);
+ checkMac(mac, testCase);
+ }
+
+ private void testSingleByte(Mac mac, TestCase testCase)
+ {
+ final byte[] ad = testCase.getAd();
+ for (int i = 0; i < ad.length; i++)
+ {
+ mac.update(ad[i]);
+ }
+ checkMac(mac, testCase);
+ }
+
+ private void checkMac(Mac mac, TestCase testCase)
+ {
+ final byte[] generatedMac = new byte[mac.getMacSize()];
+ mac.doFinal(generatedMac, 0);
+ if (!areEqual(testCase.getTag(), generatedMac))
+ {
+ fail("Failed " + testCase.getName() + " - expected " + new String(Hex.encode(testCase.getTag())) + " got "
+ + new String(Hex.encode(generatedMac)));
+ }
+ }
+
+ public String getName()
+ {
+ return "GMac";
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new GMacTest());
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/NonMemoableDigestTest.java b/src/test/java/org/bouncycastle/crypto/test/NonMemoableDigestTest.java
new file mode 100644
index 00000000..d332393b
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/test/NonMemoableDigestTest.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.crypto.test;
+
+import org.bouncycastle.crypto.digests.NonMemoableDigest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTestResult;
+import org.bouncycastle.util.test.Test;
+import org.bouncycastle.util.test.TestResult;
+
+/**
+ * SHA1 HMac Test, test vectors from RFC 2202
+ */
+public class NonMemoableDigestTest
+ implements Test
+{
+ final static String[] keys = {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4a656665",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ };
+
+ final static String[] digests = {
+ "b617318655057264e28bc0b6fb378c8ef146be00",
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
+ "125d7342b9ac11cd91a39af48aa17b4f63f175d3",
+ "4c9007f4026250c6bc8414f9bf50c86c2d7235da",
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112",
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91",
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112",
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"
+ };
+
+ final static String[] messages = {
+ "Hi There",
+ "what do ya want for nothing?",
+ "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+ "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+ "Test With Truncation",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ };
+
+ public String getName()
+ {
+ return "NonMemoableDigest";
+ }
+
+ public TestResult perform()
+ {
+ HMac hmac = new HMac(new NonMemoableDigest(new SHA1Digest()));
+ byte[] resBuf = new byte[hmac.getMacSize()];
+
+ for (int i = 0; i < messages.length; i++)
+ {
+ byte[] m = messages[i].getBytes();
+ if (messages[i].startsWith("0x"))
+ {
+ m = Hex.decode(messages[i].substring(2));
+ }
+ hmac.init(new KeyParameter(Hex.decode(keys[i])));
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+
+ if (!Arrays.areEqual(resBuf, Hex.decode(digests[i])))
+ {
+ return new SimpleTestResult(false, getName() + ": Vector " + i + " failed");
+ }
+ }
+
+ //
+ // test reset
+ //
+ int vector = 0; // vector used for test
+ byte[] m = messages[vector].getBytes();
+ if (messages[vector].startsWith("0x"))
+ {
+ m = Hex.decode(messages[vector].substring(2));
+ }
+ hmac.init(new KeyParameter(Hex.decode(keys[vector])));
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+ hmac.reset();
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+
+ if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector])))
+ {
+ return new SimpleTestResult(false, getName() +
+ "Reset with vector " + vector + " failed");
+ }
+
+ return new SimpleTestResult(true, getName() + ": Okay");
+ }
+
+ public static void main(
+ String[] args)
+ {
+ NonMemoableDigestTest test = new NonMemoableDigestTest();
+ TestResult result = test.perform();
+
+ System.out.println(result);
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java b/src/test/java/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java
new file mode 100755
index 00000000..50e751b7
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java
@@ -0,0 +1,61 @@
+package org.bouncycastle.crypto.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.kems.RSAKeyEncapsulation;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * Tests for the RSA Key Encapsulation Mechanism
+ */
+public class RSAKeyEncapsulationTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "RSAKeyEncapsulation";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ // Generate RSA key pair
+ RSAKeyPairGenerator rsaGen = new RSAKeyPairGenerator();
+ rsaGen.init(new RSAKeyGenerationParameters(BigInteger.valueOf(65537), new SecureRandom(), 1024, 5));
+ AsymmetricCipherKeyPair keys = rsaGen.generateKeyPair();
+
+ // Set RSA-KEM parameters
+ RSAKeyEncapsulation kem;
+ KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest());
+ SecureRandom rnd = new SecureRandom();
+ byte[] out = new byte[128];
+ KeyParameter key1, key2;
+
+ // Test RSA-KEM
+ kem = new RSAKeyEncapsulation(kdf, rnd);
+
+ kem.init(keys.getPublic());
+ key1 = (KeyParameter)kem.encrypt(out, 128);
+
+ kem.init(keys.getPrivate());
+ key2 = (KeyParameter)kem.decrypt(out, 128);
+
+ if (!areEqual(key1.getKey(), key2.getKey()))
+ {
+ fail("failed test");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new RSAKeyEncapsulationTest());
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
index aea3003d..906eb910 100644
--- a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -96,6 +96,7 @@ public class RegressionTest
new CMacTest(),
new EAXTest(),
new GCMTest(),
+ new GMacTest(),
new HCFamilyTest(),
new HCFamilyVecTest(),
new ISAACTest(),
@@ -113,10 +114,9 @@ public class RegressionTest
new DSTU4145Test(),
new SipHashTest(),
new OCBTest(),
- new HashDRBGTest(),
- new HMacDRBGTest(),
- new CTRDRBGTest(),
- new DualECDRBGTest()
+ new NonMemoableDigestTest(),
+ new RSAKeyEncapsulationTest(),
+ new ECIESKeyEncapsulationTest()
};
public static void main(
diff --git a/src/test/java/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java b/src/test/java/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java
index 9f7f5342..542e6e6b 100644
--- a/src/test/java/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.WhirlpoolDigest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
@@ -11,44 +12,42 @@ import org.bouncycastle.util.test.SimpleTest;
*
*/
public class WhirlpoolDigestTest
- extends SimpleTest
+ extends DigestTest
{
- private static String[][] _isoVectors =
+ private static String[] messages =
{
- {
- "",
- "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3"
- },
- {
- "a",
- "8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A"
- },
- {
- "abc",
- "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5"
- },
- {
- "message digest",
- "378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E"
- },
- {
- "abcdefghijklmnopqrstuvwxyz",
- "F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B"
- },
- {
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
- "DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467"
- },
- {
- "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
- "466EF18BABB0154D25B9D38A6414F5C08784372BCCB204D6549C4AFADB6014294D5BD8DF2A6C44E538CD047B2681A51A2C60481E88C5A20B2C2A80CF3A9A083B"
- },
- {
- "abcdbcdecdefdefgefghfghighijhijk",
- "2A987EA40F917061F5D6F0A0E4644F488A7A5A52DEEE656207C562F988E95C6916BDC8031BC5BE1B7B947639FE050B56939BAAA0ADFF9AE6745B7B181C3BE3FD"
- }
+ "",
+ "a",
+ "abc",
+ "message digest",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "abcdbcdecdefdefgefghfghighijhijk"
};
-
+
+ private static String[] digests =
+ {
+ "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3",
+ "8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A",
+ "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5",
+ "378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E",
+ "F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B",
+ "DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467",
+ "466EF18BABB0154D25B9D38A6414F5C08784372BCCB204D6549C4AFADB6014294D5BD8DF2A6C44E538CD047B2681A51A2C60481E88C5A20B2C2A80CF3A9A083B",
+ "2A987EA40F917061F5D6F0A0E4644F488A7A5A52DEEE656207C562F988E95C6916BDC8031BC5BE1B7B947639FE050B56939BAAA0ADFF9AE6745B7B181C3BE3FD"
+ };
+
+ WhirlpoolDigestTest()
+ {
+ super(new WhirlpoolDigest(), messages, digests);
+ }
+
+ protected Digest cloneDigest(Digest digest)
+ {
+ return new WhirlpoolDigest((WhirlpoolDigest)digest);
+ }
+
private static String _millionAResultVector = "0C99005BEB57EFF50A7CF005560DDF5D29057FD86B20BFD62DECA0F1CCEA4AF51FC15490EDDC47AF32BB2B66C34FF9AD8C6008AD677F77126953B226E4ED8B01";
private static String _thirtyOneZeros = "3E3F188F8FEBBEB17A933FEAF7FE53A4858D80C915AD6A1418F0318E68D49B4E459223CD414E0FBC8A57578FD755D86E827ABEF4070FC1503E25D99E382F72BA";
@@ -60,11 +59,7 @@ public class WhirlpoolDigestTest
public void performTest()
{
- for (int i = 0; i < _isoVectors.length; i++)
- {
- performStandardVectorTest("ISO vector test ["+i+"]", _isoVectors[i][0],
- _isoVectors[i][1]);
- }
+ super.performTest();
byte[] thirtyOneZeros = new byte[31];
performStandardVectorTest("31 zeroes test",
@@ -92,12 +87,6 @@ public class WhirlpoolDigestTest
}
}
- private void performStandardVectorTest(String testTitle, String inputBytesAsString,
- String resultsAsHex)
- {
- doPerformTest(testTitle, inputBytesAsString.getBytes(), resultsAsHex);
- }
-
private String createHexOutputFromDigest(byte[] digestBytes)
{
String resStr;
@@ -108,7 +97,6 @@ public class WhirlpoolDigestTest
resStr = new String(Hex.encode(resBuf));
return resStr;
}
-
public static void main(String[] args)
{
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java b/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
index 4ac77b8e..313f665f 100644
--- a/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
+++ b/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java
@@ -126,6 +126,7 @@ public class DESedeTest
}
private void wrapTest(
+ String alg,
int id,
byte[] kek,
byte[] iv,
@@ -134,13 +135,13 @@ public class DESedeTest
{
try
{
- Cipher wrapper = Cipher.getInstance("DESedeWrap", "BC");
+ Cipher wrapper = Cipher.getInstance(alg + "Wrap", "BC");
- wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, "DESEDE"), new IvParameterSpec(iv));
+ wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, alg), new IvParameterSpec(iv));
try
{
- byte[] cText = wrapper.wrap(new SecretKeySpec(in, "DESEDE"));
+ byte[] cText = wrapper.wrap(new SecretKeySpec(in, alg));
if (!equalArray(cText, out))
{
fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText)));
@@ -151,11 +152,11 @@ public class DESedeTest
fail("failed wrap test exception " + e.toString());
}
- wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, "DESEDE"));
+ wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, alg));
try
{
- Key pText = wrapper.unwrap(out, "DESede", Cipher.SECRET_KEY);
+ Key pText = wrapper.unwrap(out, alg, Cipher.SECRET_KEY);
if (!equalArray(pText.getEncoded(), in))
{
fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded())));
@@ -173,6 +174,7 @@ public class DESedeTest
}
public void test(
+ String alg,
int strength,
byte[] input,
byte[] output)
@@ -191,19 +193,19 @@ public class DESedeTest
try
{
- keyGen = KeyGenerator.getInstance("DESEDE", "BC");
+ keyGen = KeyGenerator.getInstance(alg, "BC");
keyGen.init(strength, rand);
key = keyGen.generateKey();
- in = Cipher.getInstance("DESEDE/ECB/PKCS7Padding", "BC");
- out = Cipher.getInstance("DESEDE/ECB/PKCS7Padding", "BC");
+ in = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC");
+ out = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC");
out.init(Cipher.ENCRYPT_MODE, key, rand);
}
catch (Exception e)
{
- fail("DESEDE failed initialisation - " + e.toString());
+ fail(alg + " failed initialisation - " + e.toString());
}
try
@@ -212,7 +214,7 @@ public class DESedeTest
}
catch (Exception e)
{
- fail("DESEDE failed initialisation - " + e.toString());
+ fail(alg + " failed initialisation - " + e.toString());
}
//
@@ -233,7 +235,7 @@ public class DESedeTest
}
catch (IOException e)
{
- fail("DESEDE failed encryption - " + e.toString());
+ fail(alg + " failed encryption - " + e.toString());
}
byte[] bytes;
@@ -242,7 +244,7 @@ public class DESedeTest
if (!equalArray(bytes, output))
{
- fail("DESEDE failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
+ fail(alg + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
}
//
@@ -266,12 +268,12 @@ public class DESedeTest
}
catch (Exception e)
{
- fail("DESEDE failed encryption - " + e.toString());
+ fail(alg + " failed encryption - " + e.toString());
}
if (!equalArray(bytes, input))
{
- fail("DESEDE failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
+ fail(alg + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
}
//
@@ -279,17 +281,17 @@ public class DESedeTest
//
try
{
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede", "BC");
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg, "BC");
DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class);
if (!equalArray(key.getEncoded(), keySpec.getKey(), 16))
{
- fail("DESEDE KeySpec does not match key.");
+ fail(alg + " KeySpec does not match key.");
}
}
catch (Exception e)
{
- fail("DESEDE failed keyspec - " + e.toString());
+ fail(alg + " failed keyspec - " + e.toString());
}
}
@@ -297,7 +299,12 @@ public class DESedeTest
{
for (int i = 0; i != cipherTests1.length; i += 2)
{
- test(Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1]));
+ test("DESEDE", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1]));
+ }
+
+ for (int i = 0; i != cipherTests1.length; i += 2)
+ {
+ test("TDEA", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1]));
}
byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f");
@@ -305,7 +312,8 @@ public class DESedeTest
byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98");
byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4");
- wrapTest(1, kek1, iv1, in1, out1);
+ wrapTest("DESEDE", 1, kek1, iv1, in1, out1);
+ wrapTest("TDEA", 1, kek1, iv1, in1, out1);
}
public static void main(
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java b/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java
index 2a81b387..e0478997 100644
--- a/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java
+++ b/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java
@@ -477,9 +477,6 @@ public class DSATest
private void testECDSA239bitBinary(String algorithm, DERObjectIdentifier oid)
throws Exception
{
-// BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
-// BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
-
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
SecureRandom k = new FixedSecureRandom(kData);
@@ -828,6 +825,117 @@ public class DSATest
}
}
+ private void testDSA2Parameters()
+ throws Exception
+ {
+ byte[] seed = Hex.decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0");
+
+ AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DSA", "BC");
+ a.init(2048, new DSATestSecureRandom(seed));
+ AlgorithmParameters params = a.generateParameters();
+
+ DSAParameterSpec dsaP = (DSAParameterSpec)params.getParameterSpec(DSAParameterSpec.class);
+
+ if (!dsaP.getQ().equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16)))
+ {
+ fail("Q incorrect");
+ }
+
+ if (!dsaP.getP().equals(new BigInteger(
+ "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+ "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+ "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+ "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+ "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+ "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+ "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+ "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+ "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+ "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+ "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16)))
+ {
+ fail("P incorrect");
+ }
+
+ if (!dsaP.getG().equals(new BigInteger(
+ "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+ "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+ "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+ "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+ "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+ "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+ "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+ "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+ "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+ "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+ "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)))
+ {
+ fail("G incorrect");
+ }
+
+ KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC");
+ g.initialize(dsaP, new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")));
+ KeyPair p = g.generateKeyPair();
+
+ DSAPrivateKey sKey = (DSAPrivateKey)p.getPrivate();
+ DSAPublicKey vKey = (DSAPublicKey)p.getPublic();
+
+ if (!vKey.getY().equals(new BigInteger(
+ "2828003D7C747199143C370FDD07A286" +
+ "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+ "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+ "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+ "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+ "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+ "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+ "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+ "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+ "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+ "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16)))
+ {
+ fail("Y value incorrect");
+ }
+
+ if (!sKey.getX().equals(
+ new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16)))
+ {
+ fail("X value incorrect");
+ }
+
+ byte[] encodeParams = params.getEncoded();
+
+ AlgorithmParameters a2 = AlgorithmParameters.getInstance("DSA", "BC");
+ a2.init(encodeParams);
+
+ // a and a2 should be equivalent!
+ byte[] encodeParams_2 = a2.getEncoded();
+
+ if (!areEqual(encodeParams, encodeParams_2))
+ {
+ fail("encode/decode parameters failed");
+ }
+
+ Signature s = Signature.getInstance("DSA", "BC");
+ byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+ s.initSign(sKey);
+
+ s.update(data);
+
+ byte[] sigBytes = s.sign();
+
+ s = Signature.getInstance("DSA", "BC");
+
+ s.initVerify(vKey);
+
+ s.update(data);
+
+ if (!s.verify(sigBytes))
+ {
+ fail("DSA verification failed");
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -845,9 +953,12 @@ public class DSATest
testECDSA239bitBinary("SHA1withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
testECDSA239bitBinary("SHA224withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
testECDSA239bitBinary("SHA256withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-
+ testECDSA239bitBinary("SHA384withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+ testECDSA239bitBinary("SHA512withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+
testGeneration();
testParameters();
+ testDSA2Parameters();
}
protected BigInteger[] derDecode(
@@ -878,4 +989,28 @@ public class DSATest
runTest(new DSATest());
}
+
+ private class DSATestSecureRandom
+ extends FixedSecureRandom
+ {
+ private boolean first = true;
+
+ public DSATestSecureRandom(byte[] value)
+ {
+ super(value);
+ }
+
+ public void nextBytes(byte[] bytes)
+ {
+ if (first)
+ {
+ super.nextBytes(bytes);
+ first = false;
+ }
+ else
+ {
+ bytes[bytes.length - 1] = 2;
+ }
+ }
+ }
}
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java b/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java
new file mode 100644
index 00000000..72a4888a
--- /dev/null
+++ b/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java
@@ -0,0 +1,145 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestFailedException;
+
+public class GMacTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "GMac";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ checkRegistrations();
+ }
+
+ private void checkRegistrations()
+ throws Exception
+ {
+ List<String> missingMacs = new ArrayList<String>();
+ List<String> missingKeyGens = new ArrayList<String>();
+
+ String[] ciphers = new String[] { "AES", "NOEKEON", "Twofish", "CAST6", "SEED", "Serpent", "RC6", "CAMELLIA" };
+ String[] macs = new String[]
+ {
+ "a52308801b32d4770c701ace9b826f12",
+ "cf11dacaf6024a78dba76b256e23caab",
+ "13db7c428e5a7128149b5ec782d07fac",
+ "d13a33e78e48b274bf7d64bf9aecdb82",
+ "d05d550054735c6e7e01b6981fc14b4e",
+ "4a34dfe4f5410afd7c40b1e110377a73",
+ "d9f597c96b41f641da6c83d4760f543b",
+ "371ad8cc920c6bda2a26d8f237bd446b"
+ };
+
+ for (int i = 0; i < ciphers.length; i++)
+ {
+ String cipherName = ciphers[i];
+ Cipher cipher;
+ try
+ {
+ cipher = Cipher.getInstance(cipherName, "BC");
+ }
+ catch (Exception e)
+ {
+ System.err.println(cipherName + ": " + e.getMessage());
+ continue;
+ }
+ int blocksize;
+ try
+ {
+ blocksize = cipher.getBlockSize();
+ }
+ catch (Exception e)
+ {
+ System.err.println(cipherName + ": " + e.getMessage());
+ continue;
+ }
+ // GCM is defined over 128 bit block ciphers
+ if (blocksize == 16)
+ {
+ String macName = cipherName + "-GMAC";
+ String macNameAlt = cipherName + "GMAC";
+
+ // Check we have a GMAC registered for each name
+ checkMac(macName, missingMacs, missingKeyGens, macs[i]);
+ checkMac(macNameAlt, missingMacs, missingKeyGens, macs[i]);
+ }
+ }
+ if (missingMacs.size() != 0)
+ {
+ fail("Did not find GMAC registrations for the following ciphers: " + missingMacs);
+ }
+ if (missingKeyGens.size() != 0)
+ {
+ Collections.sort(missingKeyGens);
+ fail("Did not find GMAC KeyGenerator registrations for the following macs: " + missingKeyGens);
+ }
+ }
+
+ private void checkMac(String name, List<String> missingMacs, List<String> missingKeyGens, String macOutput)
+ {
+ try
+ {
+ Mac mac = Mac.getInstance(name);
+
+ mac.init(new SecretKeySpec(new byte[mac.getMacLength()], mac.getAlgorithm()), new IvParameterSpec(
+ new byte[16]));
+ mac.update(new byte[128]);
+ byte[] bytes = mac.doFinal();
+
+ if (!Arrays.areEqual(bytes, Hex.decode(macOutput)))
+ {
+ fail("wrong mac value computed for " + name);
+ }
+
+ try
+ {
+ KeyGenerator kg = KeyGenerator.getInstance(name);
+ kg.generateKey();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ missingKeyGens.add(name);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ missingMacs.add(name);
+ }
+ catch (TestFailedException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected error", e);
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new GMacTest());
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java b/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java
new file mode 100644
index 00000000..9c0805a8
--- /dev/null
+++ b/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+abstract class JceTestUtil
+{
+ private JceTestUtil()
+ {
+ }
+
+ static String[] getRegisteredAlgorithms(String prefix, String[] exclusionPatterns)
+ {
+ final BouncyCastleProvider prov = (BouncyCastleProvider)Security.getProvider("BC");
+
+ List matches = new ArrayList();
+ Enumeration algos = prov.keys();
+ while (algos.hasMoreElements())
+ {
+ String algo = (String)algos.nextElement();
+ if (!algo.startsWith(prefix))
+ {
+ continue;
+ }
+ String algoName = algo.substring(prefix.length());
+ if (!isExcluded(algoName, exclusionPatterns))
+ {
+ matches.add(algoName);
+ }
+ }
+ return (String[])matches.toArray(new String[matches.size()]);
+ }
+
+ private static boolean isExcluded(String algoName, String[] exclusionPatterns)
+ {
+ for (int i = 0; i < exclusionPatterns.length; i++)
+ {
+ if (algoName.contains(exclusionPatterns[i]))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java b/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
index 52026bdb..85972a05 100644
--- a/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
@@ -67,6 +67,7 @@ public class RegressionTest
new SigNameTest(),
new MQVTest(),
new CMacTest(),
+ new GMacTest(),
new DSTU4145Test(),
new CRL5Test(),
new SipHashTest(),
diff --git a/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java b/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java
index 46853110..8e044aff 100644
--- a/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java
+++ b/src/test/java/org/bouncycastle/openpgp/test/PGPKeyRingTest.java
@@ -11,6 +11,8 @@ import java.util.Iterator;
import javax.crypto.Cipher;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;
import org.bouncycastle.openpgp.PGPEncryptedData;
@@ -25,8 +27,10 @@ import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -1095,6 +1099,48 @@ public class PGPKeyRingTest
"iYW7+SWY76AAl+gmWIMm2jbN8bZXFk4jmIxpycHCrtoXX8rUk/0+se8NvbmAdMGK" +
"POOoD7oxdRmJSU5hSspOCHrCwCa3");
+
+ // Key from http://www.angelfire.com/pr/pgpf/pgpoddities.html
+ private static final char[] v3KeyPass = "test@key.test".toCharArray();
+
+ private static final byte[] pubv3 = Base64.decode(
+ "mQENAzroPPgAAAEIANnTx/gHfag7qRMG6cVUnYZJjLcsdF6JSaVs+PUDCZ8l2+Z2" +
+ "V9tgxByp26bymIlq5qFFeoA5vCiKc8qzYiEVLJVVIIDjw/id2gq/TgmxoLAwiDQM" +
+ "TUKdCFa6pmR/uaxyrnJxfUA7+Qh0R0OjoCxNlrmyO3eiKstsJGqSUFIQq7GhcHc4" +
+ "nbV59zHhEWnH7DX7sDa9CgF11WxM3sjWp15iOoP1nixhmchDtQ7foUxLsCF36G/4" +
+ "ijcbN2NjiCDYMFburN8fXgrQzYHAIIiVFE0J+fbXNfPRmnbhQdaC8rIdiQ3tExBb" +
+ "N0qWhGPT9M4JOZd1yPdFMb9gbntd8VZkiPd6/3sABRG0FHRlc3QgPHRlc3RAa2V5" +
+ "LnRlc3Q+iQEVAwUQOug8+PFWZIj3ev97AQH7NQgAo3sH+KcsPtAbyp5U02J9h3Ro" +
+ "aiKpAYxg3rfUVo/RH6hmCWT/AlPHLPZZC/tKiPkuIm2V3Xqyum530N0sBYxNzgNp" +
+ "us8mK9QurYj2omKzf1ltN+uNHR8vjB8s7jEd/CDCARu81PqNoVq2b9JRFGpGbAde" +
+ "7kQ/a0r2/IsJ8fz0iSpCH0geoHt3sBk9MyEem4uG0e2NzlH2wBz4H8l8BNHRHBq0" +
+ "6tGH4h11ZhH3FiNzJWibT2AvzLCqar2qK+6pohKSvIp8zEP7Y/iQzCvkuOfHsUOH" +
+ "4Utgg85k09hRDZ3pRRL/4R+Z+/1uXb+n6yKbOmpmi7U7wc9IwZxtTlGXsNIf+Q=="
+ );
+
+ private static final byte[] privv3 = Base64.decode(
+ "lQOgAzroPPgAAAEIANnTx/gHfag7qRMG6cVUnYZJjLcsdF6JSaVs+PUDCZ8l2+Z2" +
+ "V9tgxByp26bymIlq5qFFeoA5vCiKc8qzYiEVLJVVIIDjw/id2gq/TgmxoLAwiDQM" +
+ "TUKdCFa6pmR/uaxyrnJxfUA7+Qh0R0OjoCxNlrmyO3eiKstsJGqSUFIQq7GhcHc4" +
+ "nbV59zHhEWnH7DX7sDa9CgF11WxM3sjWp15iOoP1nixhmchDtQ7foUxLsCF36G/4" +
+ "ijcbN2NjiCDYMFburN8fXgrQzYHAIIiVFE0J+fbXNfPRmnbhQdaC8rIdiQ3tExBb" +
+ "N0qWhGPT9M4JOZd1yPdFMb9gbntd8VZkiPd6/3sABREDXB5zk3GNdSkH/+/447Kq" +
+ "hR9uM+UnZz7wDkzmt+7xbNg9F2pr/tghVCM7D0PO1YjH4DBpU1ZRO+v1t/eBB/Jd" +
+ "3lJYdlWYHOefJkBi44gNAafZ8ysPOJk6OGOjas/sr+JRFiX9Mgzrs2IDiejmuA98" +
+ "DLuSuNtzFKbE2/DDdOBEizYUjqPLlCdn5sVEt+0WKWJiAv7YonCGguWS3RKfTaYk" +
+ "9IE9SbI+qph9JsuyTD22GLv+gTMvwCkC1DVaHIVgzURpdnlyYyz4DBh3pAgg0nh6" +
+ "gpUTsjnUmrvdh+r8qj3oXH7WBMhs6qKYvU1Go5iV3S1Cu4H/Z/+s6XUFgQShevVe" +
+ "VCy0QtmWSFeySekEACHLJIdBDa8K4dcM2wvccz587D4PtKvMG5j71raOcgVY+r1k" +
+ "e6au/fa0ACqLNvn6+vFHG+Rurn8RSKV31YmTpx7J5ixTOsB+wVcwTYbrw8uNlBWc" +
+ "+IkqPwHrtdK95GIYQykfPW95PRudsOBdxwQW4Ax/WCst3fbjo0SZww0Os+3WBADJ" +
+ "/Nv0mjikXRmqJIzfuI2yxxX4Wm6vqXJkPF7LGtSMB3VEJ3qPsysoai5TYboxA8C1" +
+ "4rQjIoQjA+87gxZ44PUVxrxBonITCLXJ3GsvDQ2PNhS6WQ9Cf89vtYW1vLW65Nex" +
+ "+7AuVRepKhx6Heqdf7S03m6UYliIglrEzgEWM1XrOwP/gLMsme4h0LjLgKfd0LBk" +
+ "qSMdu21VSl60TMTjxav149AdutzuCVa/yPBM/zLQdlvQoGYg2IbN4+7gDHKURcSx" +
+ "DgOAzCcEZxdMvRk2kaOI5RRf5gV9e+ErvEMzJ/xT8xWsi+aLOhaDMbwq2LLiK2L+" +
+ "tXV/Z3H/Ot4u3E7H+6fHPElFYbQUdGVzdCA8dGVzdEBrZXkudGVzdD4="
+ );
+
public void test1()
throws Exception
{
@@ -1220,7 +1266,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1380,7 +1426,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1501,7 +1547,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1547,7 +1593,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1653,7 +1699,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1830,7 +1876,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1876,7 +1922,7 @@ public class PGPKeyRingTest
byte[] bytes = pgpSec.getEncoded();
- pgpSec = new PGPSecretKeyRing(bytes);
+ pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator());
Iterator it = pgpSec.getSecretKeys();
while (it.hasNext())
@@ -1907,7 +1953,7 @@ public class PGPKeyRingTest
public void test10()
throws Exception
{
- PGPSecretKeyRing secretRing = new PGPSecretKeyRing(sec10);
+ PGPSecretKeyRing secretRing = new PGPSecretKeyRing(sec10, new JcaKeyFingerprintCalculator());
Iterator secretKeys = secretRing.getSecretKeys();
while (secretKeys.hasNext())
@@ -2182,23 +2228,23 @@ public class PGPKeyRingTest
private void rewrapTest()
throws Exception
{
- SecureRandom rand = new SecureRandom();
-
// Read the secret key rings
PGPSecretKeyRingCollection privRings = new PGPSecretKeyRingCollection(
new ByteArrayInputStream(rewrapKey));
+ char[] newPass = "fred".toCharArray();
Iterator rIt = privRings.getKeyRings();
if (rIt.hasNext())
{
- PGPSecretKeyRing pgpPriv = (PGPSecretKeyRing)rIt.next();
+ PGPSecretKeyRing pgpPriv= (PGPSecretKeyRing)rIt.next();
Iterator it = pgpPriv.getSecretKeys();
while (it.hasNext())
{
PGPSecretKey pgpKey = (PGPSecretKey)it.next();
+ long oldKeyID = pgpKey.getKeyID();
// re-encrypt the key with an empty password
pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey);
@@ -2210,6 +2256,100 @@ public class PGPKeyRingTest
// this should succeed
PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null);
+
+ if (pgpKey.getKeyID() != oldKeyID)
+ {
+ fail("key ID mismatch");
+ }
+ }
+
+ it = pgpPriv.getSecretKeys();
+
+ while (it.hasNext())
+ {
+ PGPSecretKey pgpKey = (PGPSecretKey)it.next();
+ long oldKeyID = pgpKey.getKeyID();
+
+ // re-encrypt the key with an empty password
+ pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey);
+ pgpKey = PGPSecretKey.copyWithNewPassword(
+ pgpKey,
+ null,
+ new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setProvider("BC").build(newPass));
+ pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey);
+
+ // this should succeed
+ PGPPrivateKey privTmp = pgpKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build()).setProvider("BC").build(newPass));
+
+ if (pgpKey.getKeyID() != oldKeyID)
+ {
+ fail("key ID mismatch");
+ }
+ }
+ }
+ }
+
+ private void rewrapTestV3()
+ throws Exception
+ {
+ // Read the secret key rings
+ PGPSecretKeyRingCollection privRings = new PGPSecretKeyRingCollection(
+ new ByteArrayInputStream(privv3));
+ char[] newPass = "fred".toCharArray();
+
+ Iterator rIt = privRings.getKeyRings();
+
+ if (rIt.hasNext())
+ {
+ PGPSecretKeyRing pgpPriv = (PGPSecretKeyRing)rIt.next();
+
+ Iterator it = pgpPriv.getSecretKeys();
+
+ while (it.hasNext())
+ {
+ PGPSecretKey pgpKey = (PGPSecretKey)it.next();
+ long oldKeyID = pgpKey.getKeyID();
+
+ // re-encrypt the key with an empty password
+ pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey);
+
+ pgpKey = PGPSecretKey.copyWithNewPassword(
+ pgpKey,
+ new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build()).setProvider("BC").build(v3KeyPass),
+ null);
+ pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey);
+
+ // this should succeed
+ PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null);
+
+ if (pgpKey.getKeyID() != oldKeyID)
+ {
+ fail("key ID mismatch");
+ }
+ }
+
+ it = pgpPriv.getSecretKeys();
+
+ while (it.hasNext())
+ {
+ PGPSecretKey pgpKey = (PGPSecretKey)it.next();
+ long oldKeyID = pgpKey.getKeyID();
+
+ // re-encrypt the key with an empty password
+ pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey);
+ pgpKey = PGPSecretKey.copyWithNewPassword(
+ pgpKey,
+ null,
+ new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5, new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build().get(HashAlgorithmTags.MD5)).setProvider("BC").build(newPass));
+ pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey);
+
+ // this should succeed
+ PGPPrivateKey privTmp = pgpKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build()).setProvider("BC").build(newPass));
+
+ if (pgpKey.getKeyID() != oldKeyID)
+ {
+ fail("key ID mismatch");
+ }
}
}
}
@@ -2367,6 +2507,7 @@ public class PGPKeyRingTest
generateTest();
generateSha1Test();
rewrapTest();
+ rewrapTestV3();
testPublicKeyRingWithX509();
testSecretKeyRingWithPersonalCertificate();
insertMasterTest();
diff --git a/src/test/java/org/bouncycastle/openpgp/test/PGPNoPrivateKeyTest.java b/src/test/java/org/bouncycastle/openpgp/test/PGPNoPrivateKeyTest.java
new file mode 100644
index 00000000..be69d111
--- /dev/null
+++ b/src/test/java/org/bouncycastle/openpgp/test/PGPNoPrivateKeyTest.java
@@ -0,0 +1,167 @@
+package org.bouncycastle.openpgp.test;
+
+import java.security.Security;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class PGPNoPrivateKeyTest
+ extends SimpleTest
+{
+ String pgpOldPass = "test";
+ String pgpNewPass = "newtest";
+ String BOUNCY_CASTLE_PROVIDER_NAME = "BC";
+
+ byte[] pgpPrivateEmpty = Base64.decode(
+ "lQCVBFGSNGwBBACwABZRIEW/4vDQajcO0FW39yNDcsHBDwPkGT95D7jiVTTRoSs6"
+ + "ACWRAAwGlz4V62U0+nEgasxpifHnu6jati5zxwS16qNvBcxcqZrdZWdvolzCWWsr"
+ + "pFd0juhwesrvvUb5dN/xCJKyLPkp6A+uwv35/cxVSOHFvbW7nnronwinYQARAQAB"
+ + "/gJlAkdOVQG0HlRlc3QgVGVzdGVyc29uIDx0ZXN0QHRlc3QubmV0Poi4BBMBAgAi"
+ + "BQJRkjRsAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDSr6Hh9tuk5NfI"
+ + "A/4iMPF9k2/7KanWksNrBqhKemsyI7hLTxAwv+AA9B0rOO2QoJYe9OjuKn199fNO"
+ + "JPsAgwy7okvDe3QAUz3WA9GlghM5STYvonFJtl7o4kyjcZ4HO2ZI5Bdc5O9i63QA"
+ + "rNv40qVp++A3Mf+13z7cftKufj0vOfw6YeayLVXcV4h95J0B/gRRkjSNAQQA2l3d"
+ + "ZnFFYXYDoNHz1cOX4787CbKdBIfiALFfdbyQ6TzYkCTJTnVCZlQs2aeyrcdTSZUx"
+ + "N4y9bih4nfJ8uRKyQvLm6O0u6bG16kUDDnnwlsGn3uvTXfUwnSPq8pFY2acde6ZG"
+ + "N25vezNK1R6C7kU3+puNHqBIRANfHTsBElaD2V0AEQEAAf4CAwIUI0+QlwBVFdNa"
+ + "S/ppOwSht7Gr19AK4SHe92VWDKnCBPN2W3vhM4NcZSQCV2oiEMI0akLZ26jqCiRl"
+ + "AvTjLSVDho1rUWbaSxFfKlDQNbxCJKlMQeVfbsWXJMeDkn1AhPru3PBLl6Y1jocd"
+ + "vIVM7aQugNQlwEuFWgtZeODxcgBfX2lQeEMIv0AtWTAMt6MVT8AgnFqiqC4+14t0"
+ + "j2CHP2hqCDr5zw9gerAYQ0F03OS34vDm4Y5DmQFjyB05QO2cIN4DZ9gJg8NAQT+P"
+ + "+bwWR3/i9pTq3InNkoi2uT41OnHsYWgKoEQn62BDxjbvO359crUiq9VvS52v2UXh"
+ + "b6Z+fF3PoXXsobS1QQwTPXAeA/mlAflTp+HrkckatY7DgWbON1SSn4Z1XcWPKBSY"
+ + "epS5+90Tj3byZvN7Laj61ZlXVBvU3x7z6MaBZDf4479fklcUnJ13v+P6uGnTI4YE"
+ + "Q5pPjHn1dDqD2Nl8ZW9ufK9pPYkBPQQYAQIACQUCUZI0jQIbAgCoCRDSr6Hh9tuk"
+ + "5J0gBBkBAgAGBQJRkjSNAAoJEPIU7wJ5Ws2K0F0D/jHx4jrZq7SCv69/4hictjgz"
+ + "nNNFSOm20/brHXMBdp6p9mBqt28WU8fgRkxS0mz+1i7VNTv6ZwUXawfTyOVCPR5B"
+ + "QEC+FA+LvdX0UcJBJpa9tT4koz1JBxmppxxLYdS2A5sslPD5If8QHUaOMEX9O1I+"
+ + "So3rEh3+DuhQj88FUuG8uJAD/3Xtpf/5nEpghLOZdQ/7QkLCoRZk7fwjChQNFSJU"
+ + "5xiZbZ/GsSvU1IqAP/NZBmBO0qDm5m7ahXy71O1bMFtaiUaw2Mb7dwqqDvppbjIB"
+ + "OHdIhSnAorRLcnjm8z51QVMzHmgvKt5/e1q1fzsVzza6DWtYr2X/1VsuouSC1uz1"
+ + "nPdgnQH+BFGSNJ4BBAC3KliQlchs0rctsXbhA/GEfiO0s9tAgVsfJL1PWUkC+26M"
+ + "yBbqkVg5RV+J6dyTSeT6cDI8PMu8XFPO6H2WWdovfs7X9K1lxfnNWxQB2L6t2xre"
+ + "XyFqvTsYEFuGvYmbNyUYvA+daHD0xqX8UrC0J6TYg5ie5I685X8gFKVEtGYG/wAR"
+ + "AQAB/gIDAuMt34hcdJPX03uBj9LtjcnrMNLyF7PVJv4wBXEt7T9Kp8cYZ80Sxpd2"
+ + "11LHzjgiPg1kkkImJ9Ie1qbPZjc9tyiGf47m0TIORnKtwNb2YN+sKLpqZ+ienfTs"
+ + "vc0uyuVGW+8PCt409M9R++0q66sxvb3oKBp2zsr3BbGaISs4OVxY2L8uU3t5j9pi"
+ + "qKdV2XTiV9OZJ+2f1au1tMwhNPzjVJ4GH53TxewSkshRJTZtw2ouUJkdA/bizfNO"
+ + "9XYYvV8sW1/ASe1dnOs+ANDGzumzSA00dWPSveURroG+ZtVXVgkakJJtDwdAYutP"
+ + "kSm28cnsl1OmrBKPonB5N3uDjTlq56vji1d2F5ugAXTTD5PptiML1wEB/TqsRJRX"
+ + "uY7DLy+8iukOVOyoVw63UMX27YUz61JJZYcB7U28gNeRyBsnTEbjmvteoFsYnaGg"
+ + "Owgc+1Zx4rQdZEqxZRmfwmiUgHGyI9OpvoVaTIuDIqDd2ZRWiJ8EGAECAAkFAlGS"
+ + "NJ4CGwwACgkQ0q+h4fbbpOScsgQAmMymSfAmltnHQzKr5k2GvlAqIzl9MqKVm9wA"
+ + "0Cx3grwzPaiqmfspPIueQ8Phexiy6dwfPrwNoKnJOEjM6/sOcWEmLiIoYi+/oQjU"
+ + "12zwogOfzT/1hPpG5zs+GBGX4sorCK663PuovwCEoNrWm+7nItfTwdnFavNuj7s4"
+ + "+b3JLdM=");
+
+ byte[] pgpPrivateFull = Base64.decode(
+ "lQH+BFGSNGwBBACwABZRIEW/4vDQajcO0FW39yNDcsHBDwPkGT95D7jiVTTRoSs6"
+ + "ACWRAAwGlz4V62U0+nEgasxpifHnu6jati5zxwS16qNvBcxcqZrdZWdvolzCWWsr"
+ + "pFd0juhwesrvvUb5dN/xCJKyLPkp6A+uwv35/cxVSOHFvbW7nnronwinYQARAQAB"
+ + "/gIDAuqTuDp/Chfq0TKnSxmm2ZpDuiHD+NFVnCyNuJpvCQk0PnVwmGMH4xvsAZB2"
+ + "TOrfh2XHf/n9J4vjxB6p6Zs1kGBgg9hcHoWf+oEf1Tz/PE/c1tUXG2Hz9wlAgstU"
+ + "my2NpDTYUjQs45p+LaM+WFtLNXzBeqELKlMevs8Xb7n+VHwiTuM3KfXETLCoLz0Q"
+ + "3GmmpOuNnvXBdza7RsDwke0r66HzwX4Le8cMH9Pe7kSMakx9S1UR/uIsxsZYZOKb"
+ + "BieGEumxiAnew0Ri5/8wTd5yYC7BWbYvBUgdMQ1gzkzmJcVky8NVfoZKQ0GkdvMo"
+ + "fMThIVXN1U6+aqzAuUMFCPYQ7fEpfoNLhCnzQPv3RE7Wo2vFMjWBod2J4MSLhBuq"
+ + "Ut+FYLqYqU21Qe4PEyPmGnkVu7Wd8FGjBF+IKZg+ycPi++h/twloD/h7LEaq907C"
+ + "4R3rdOzjZnefDfxVWjLLhqKSSuXxtjSSKwMNdbjYVVJ/tB5UZXN0IFRlc3RlcnNv"
+ + "biA8dGVzdEB0ZXN0Lm5ldD6IuAQTAQIAIgUCUZI0bAIbAwYLCQgHAwIGFQgCCQoL"
+ + "BBYCAwECHgECF4AACgkQ0q+h4fbbpOTXyAP+IjDxfZNv+ymp1pLDawaoSnprMiO4"
+ + "S08QML/gAPQdKzjtkKCWHvTo7ip9ffXzTiT7AIMMu6JLw3t0AFM91gPRpYITOUk2"
+ + "L6JxSbZe6OJMo3GeBztmSOQXXOTvYut0AKzb+NKlafvgNzH/td8+3H7Srn49Lzn8"
+ + "OmHmsi1V3FeIfeSdAf4EUZI0jQEEANpd3WZxRWF2A6DR89XDl+O/OwmynQSH4gCx"
+ + "X3W8kOk82JAkyU51QmZULNmnsq3HU0mVMTeMvW4oeJ3yfLkSskLy5ujtLumxtepF"
+ + "Aw558JbBp97r0131MJ0j6vKRWNmnHXumRjdub3szStUegu5FN/qbjR6gSEQDXx07"
+ + "ARJWg9ldABEBAAH+AgMCFCNPkJcAVRXTWkv6aTsEobexq9fQCuEh3vdlVgypwgTz"
+ + "dlt74TODXGUkAldqIhDCNGpC2duo6gokZQL04y0lQ4aNa1Fm2ksRXypQ0DW8QiSp"
+ + "TEHlX27FlyTHg5J9QIT67tzwS5emNY6HHbyFTO2kLoDUJcBLhVoLWXjg8XIAX19p"
+ + "UHhDCL9ALVkwDLejFU/AIJxaoqguPteLdI9ghz9oagg6+c8PYHqwGENBdNzkt+Lw"
+ + "5uGOQ5kBY8gdOUDtnCDeA2fYCYPDQEE/j/m8Fkd/4vaU6tyJzZKItrk+NTpx7GFo"
+ + "CqBEJ+tgQ8Y27zt+fXK1IqvVb0udr9lF4W+mfnxdz6F17KG0tUEMEz1wHgP5pQH5"
+ + "U6fh65HJGrWOw4FmzjdUkp+GdV3FjygUmHqUufvdE4928mbzey2o+tWZV1Qb1N8e"
+ + "8+jGgWQ3+OO/X5JXFJydd7/j+rhp0yOGBEOaT4x59XQ6g9jZfGVvbnyvaT2JAT0E"
+ + "GAECAAkFAlGSNI0CGwIAqAkQ0q+h4fbbpOSdIAQZAQIABgUCUZI0jQAKCRDyFO8C"
+ + "eVrNitBdA/4x8eI62au0gr+vf+IYnLY4M5zTRUjpttP26x1zAXaeqfZgardvFlPH"
+ + "4EZMUtJs/tYu1TU7+mcFF2sH08jlQj0eQUBAvhQPi73V9FHCQSaWvbU+JKM9SQcZ"
+ + "qaccS2HUtgObLJTw+SH/EB1GjjBF/TtSPkqN6xId/g7oUI/PBVLhvLiQA/917aX/"
+ + "+ZxKYISzmXUP+0JCwqEWZO38IwoUDRUiVOcYmW2fxrEr1NSKgD/zWQZgTtKg5uZu"
+ + "2oV8u9TtWzBbWolGsNjG+3cKqg76aW4yATh3SIUpwKK0S3J45vM+dUFTMx5oLyre"
+ + "f3tatX87Fc82ug1rWK9l/9VbLqLkgtbs9Zz3YJ0B/gRRkjSeAQQAtypYkJXIbNK3"
+ + "LbF24QPxhH4jtLPbQIFbHyS9T1lJAvtujMgW6pFYOUVfienck0nk+nAyPDzLvFxT"
+ + "zuh9llnaL37O1/StZcX5zVsUAdi+rdsa3l8har07GBBbhr2JmzclGLwPnWhw9Mal"
+ + "/FKwtCek2IOYnuSOvOV/IBSlRLRmBv8AEQEAAf4CAwLjLd+IXHST19N7gY/S7Y3J"
+ + "6zDS8hez1Sb+MAVxLe0/SqfHGGfNEsaXdtdSx844Ij4NZJJCJifSHtamz2Y3Pbco"
+ + "hn+O5tEyDkZyrcDW9mDfrCi6amfonp307L3NLsrlRlvvDwreNPTPUfvtKuurMb29"
+ + "6Cgads7K9wWxmiErODlcWNi/LlN7eY/aYqinVdl04lfTmSftn9WrtbTMITT841Se"
+ + "Bh+d08XsEpLIUSU2bcNqLlCZHQP24s3zTvV2GL1fLFtfwEntXZzrPgDQxs7ps0gN"
+ + "NHVj0r3lEa6BvmbVV1YJGpCSbQ8HQGLrT5EptvHJ7JdTpqwSj6JweTd7g405auer"
+ + "44tXdheboAF00w+T6bYjC9cBAf06rESUV7mOwy8vvIrpDlTsqFcOt1DF9u2FM+tS"
+ + "SWWHAe1NvIDXkcgbJ0xG45r7XqBbGJ2hoDsIHPtWceK0HWRKsWUZn8JolIBxsiPT"
+ + "qb6FWkyLgyKg3dmUVoifBBgBAgAJBQJRkjSeAhsMAAoJENKvoeH226TknLIEAJjM"
+ + "pknwJpbZx0Myq+ZNhr5QKiM5fTKilZvcANAsd4K8Mz2oqpn7KTyLnkPD4XsYsunc"
+ + "Hz68DaCpyThIzOv7DnFhJi4iKGIvv6EI1Nds8KIDn80/9YT6Ruc7PhgRl+LKKwiu"
+ + "utz7qL8AhKDa1pvu5yLX08HZxWrzbo+7OPm9yS3T");
+
+ public void performTest()
+ throws Exception
+ {
+ PGPSecretKeyRing pgpSecRing = new PGPSecretKeyRing(pgpPrivateFull, new JcaKeyFingerprintCalculator());
+ PGPSecretKey pgpSecKey = pgpSecRing.getSecretKey();
+ boolean isFullEmpty = pgpSecKey.isPrivateKeyEmpty();
+
+ pgpSecRing = new PGPSecretKeyRing(pgpPrivateEmpty, new JcaKeyFingerprintCalculator());
+ pgpSecKey = pgpSecRing.getSecretKey();
+ boolean isEmptyEmpty = pgpSecKey.isPrivateKeyEmpty();
+
+ //
+ // Check isPrivateKeyEmpty() is public
+ //
+
+ if (isFullEmpty || !isEmptyEmpty)
+ {
+ fail("Empty private keys not detected correctly.");
+ }
+
+ //
+ // Check copyWithNewPassword doesn't throw an exception for secret
+ // keys without private keys (PGPException: unknown S2K type: 101).
+ //
+
+ try
+ {
+ PGPSecretKey pgpChangedKey = PGPSecretKey.copyWithNewPassword(pgpSecKey,
+ new JcePBESecretKeyDecryptorBuilder(
+ new JcaPGPDigestCalculatorProviderBuilder().setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build(pgpOldPass.toCharArray()),
+ new JcePBESecretKeyEncryptorBuilder(pgpSecKey.getKeyEncryptionAlgorithm()).build(pgpNewPass.toCharArray()));
+ }
+ catch (PGPException e)
+ {
+ if (!e.getMessage().equals("no private key in this SecretKey - public key present only."))
+ {
+ fail("wrong exception.");
+ }
+ }
+ }
+
+ public String getName()
+ {
+ return "PGPNoPrivateKeyTest";
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new PGPNoPrivateKeyTest());
+ }
+}
diff --git a/src/test/java/org/bouncycastle/openpgp/test/PGPRSATest.java b/src/test/java/org/bouncycastle/openpgp/test/PGPRSATest.java
index 9b4a753f..a61681c6 100644
--- a/src/test/java/org/bouncycastle/openpgp/test/PGPRSATest.java
+++ b/src/test/java/org/bouncycastle/openpgp/test/PGPRSATest.java
@@ -550,8 +550,8 @@ public class PGPRSATest
private void embeddedJpegTest()
throws Exception
{
- PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey);
- PGPSecretKeyRing pgpSec = new PGPSecretKeyRing(testPrivKey);
+ PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator());
+ PGPSecretKeyRing pgpSec = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator());
PGPPublicKey pubKey = pgpPub.getPublicKey();
@@ -887,7 +887,7 @@ public class PGPRSATest
if (!noIDEA())
{
- PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKeyV3);
+ PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKeyV3, new JcaKeyFingerprintCalculator());
PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(passP, "BC");
//
@@ -907,7 +907,7 @@ public class PGPRSATest
//
// Read the private key
//
- PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKey);
+ PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator());
PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(pass, "BC");
//
@@ -979,7 +979,7 @@ public class PGPRSATest
//
// encrypted message - read subkey
//
- pgpPriv = new PGPSecretKeyRing(subKey);
+ pgpPriv = new PGPSecretKeyRing(subKey, new JcaKeyFingerprintCalculator());
//
// encrypted message
diff --git a/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java b/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
index 1a01b531..2810cb96 100644
--- a/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java
@@ -23,7 +23,8 @@ public class RegressionTest
new PGPArmoredTest(),
new PGPSignatureTest(),
new PGPClearSignedSignatureTest(),
- new PGPCompressionTest()
+ new PGPCompressionTest(),
+ new PGPNoPrivateKeyTest()
};
public static void main(