summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java56
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/crmf/test/AllTests.java103
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java7
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java22
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntrySelectorFactory.java9
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/dane/TruncatingDigestCalculator.java60
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java62
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java6
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java2
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/path/test/CertPathValidationTest.java12
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java22
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/test/CertTest.java126
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/test/DANETest.java5
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cert/test/SHA256DigestCalculator.java (renamed from bcpkix/src/main/java/org/bouncycastle/cert/test/SHA224DigestCalculator.java)14
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java2
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java6
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java4
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java30
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java24
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java7
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java16
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java17
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java60
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java14
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java2
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java20
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java45
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java78
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java101
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java791
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/cms/test/NewSignedDataTest.java77
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java6
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java6
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java1
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java4
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java14
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/test/ParserTest.java18
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/openssl/test/WriterTest.java18
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java2
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java24
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java10
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java29
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java3
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java87
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java3
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/operator/test/AllTests.java56
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java5
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java5
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java7
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java10
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java27
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java169
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java6
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/test/NewTSPTest.java546
-rw-r--r--bcpkix/src/main/java/org/bouncycastle/tsp/test/ParseTest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/LICENSE.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java59
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java32
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java71
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java80
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java123
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java64
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java101
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java121
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java85
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java83
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java13
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java1
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java62
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/test/BitStringTest.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/test/MiscTest.java43
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/util/Dump.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java43
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/Xof.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/kdf/ConcatenationKDFGenerator.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012Digest.java1050
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_256Digest.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_512Digest.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java280
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java120
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/examples/DESExample.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/BCrypt.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenBSDBCrypt.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java76
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java44
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java33
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPrivateParameters.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPublicParameters.java13
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java34
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java80
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java61
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/AESWrapPadTest.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/Blake2bDigestTest.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/CipherStreamTest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/DSATest.java147
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/DSTU4145Test.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/DeterministicDSATest.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/DigestTest.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/EAXTest.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/ECGOST3410Test.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/ECNRTest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/ECTest.java505
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GCMTest.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GMacTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3410Test.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411DigestTest.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java90
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java89
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/MD5DigestTest.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/Poly1305Test.java350
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/RSABlindedTest.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/RSATest.java192
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/RegressionTest.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/SHA3HMacTest.java335
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsClient.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsServer.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/AlertDescription.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/CertificateType.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/Chacha20Poly1305.java117
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/CipherSuite.java46
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReassembler.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java51
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsClient.java1
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/ExtensionType.java49
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/HashAlgorithm.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/NameType.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/OCSPStatusRequest.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/ServerNameList.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAEADCipher.java109
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsDHUtils.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECCUtils.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java90
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsStreamCipher.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java246
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsClient.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsServer.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/tls/test/package.html5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/iana/AEADAlgorithm.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java115
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java88
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java142
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java68
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java119
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java51
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java151
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java96
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java130
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java60
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java45
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java58
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java60
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java60
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java62
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java84
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java99
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java90
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA3.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java199
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java973
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java154
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java67
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java49
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java207
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java81
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/spec/TLSKeyMaterialSpec.java76
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java1
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertParser.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/AEADTest.java135
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java781
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java215
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java1
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertTest.java100
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHIESTest.java124
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHTest.java337
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSATest.java432
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DetDSATest.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/DigestTest.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java255
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESTest.java130
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECNRTest.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ElGamalTest.java32
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/GOST3410Test.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/HMacTest.java245
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/PBETest.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/PSSTest.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/Poly1305Test.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/RSATest.java107
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/RegressionTest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigNameTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigTest.java160
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/TLSKDFTest.java159
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/test/TestUtils.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/raw/Nat128.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/raw/Nat160.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java44
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java93
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java82
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java33
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePair.java45
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePairGenerator.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java65
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java40
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCipher.java (renamed from bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java)28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java55
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Utils.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ChaCha20.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ErrorCorrection.java121
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHAgreement.java24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHExchangePairGenerator.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHKeyPairGenerator.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPrivateKeyParameters.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPublicKeyParameters.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NTT.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NewHope.java158
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Params.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Poly.java145
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Precomp.java181
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Reduce.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/HashFunctions.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Horst.java179
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Permute.java118
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Config.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyGenerationParameters.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java404
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Seed.java49
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Tree.java93
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Wots.java97
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/AllTests.java1
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java3
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java (renamed from bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePKCSCipherTest.java)24
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java161
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RegressionTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java1679
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHKey.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPrivateKey.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPublicKey.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SPHINCSKey.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NH.java33
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/SPHINCS.java34
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java176
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java181
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java125
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java152
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java54
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java45
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java161
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java137
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java59
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java67
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java116
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/KeyAgreementSpi.java104
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyFactorySpi.java116
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java61
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java101
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java153
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyFactorySpi.java116
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyPairGeneratorSpi.java85
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java11
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/KeyPairGeneratorTest.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java (renamed from bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePKCSCipherTest.java)12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java59
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java2
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256Test.java1158
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSKeySpec.java29
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java353
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java40
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java219
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java159
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java88
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java (renamed from bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java)36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java200
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SPHINCS256KeyGenParameterSpec.java45
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Arrays.java88
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Pack.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/Streams.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java308
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/test/SimpleTest.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/test/TestRandomData.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509CertificatePair.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java4
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java19
-rw-r--r--bouncycastle.version2
549 files changed, 23512 insertions, 7023 deletions
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
index ff1158e9..b12ded50 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
@@ -1,17 +1,12 @@
package org.bouncycastle.cert.crmf.jcajce;
import java.io.InputStream;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.Provider;
-import java.security.ProviderException;
-import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
-import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -21,12 +16,16 @@ import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.operator.InputDecryptor;
+import org.bouncycastle.operator.OperatorException;
+import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
public class JceAsymmetricValueDecryptorGenerator
implements ValueDecryptorGenerator
{
private PrivateKey recipientKey;
private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+ private Provider provider = null;
+ private String providerName = null;
public JceAsymmetricValueDecryptorGenerator(PrivateKey recipientKey)
{
@@ -36,6 +35,8 @@ public class JceAsymmetricValueDecryptorGenerator
public JceAsymmetricValueDecryptorGenerator setProvider(Provider provider)
{
this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+ this.provider = provider;
+ this.providerName = null;
return this;
}
@@ -43,6 +44,8 @@ public class JceAsymmetricValueDecryptorGenerator
public JceAsymmetricValueDecryptorGenerator setProvider(String providerName)
{
this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+ this.provider = null;
+ this.providerName = providerName;
return this;
}
@@ -52,48 +55,21 @@ public class JceAsymmetricValueDecryptorGenerator
{
try
{
- Key sKey = null;
-
- Cipher keyCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
-
- try
- {
- keyCipher.init(Cipher.UNWRAP_MODE, recipientKey);
- sKey = keyCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY);
- }
- catch (GeneralSecurityException e)
- {
- }
- catch (IllegalStateException e)
- {
- }
- catch (UnsupportedOperationException e)
+ JceAsymmetricKeyUnwrapper unwrapper = new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, recipientKey);
+ if (provider != null)
{
+ unwrapper.setProvider(provider);
}
- catch (ProviderException e)
+ if (providerName != null)
{
+ unwrapper.setProvider(providerName);
}
- // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
- if (sKey == null)
- {
- keyCipher.init(Cipher.DECRYPT_MODE, recipientKey);
- sKey = new SecretKeySpec(keyCipher.doFinal(encryptedContentEncryptionKey), contentEncryptionAlgorithm.getAlgorithm().getId());
- }
-
- return sKey;
- }
- catch (InvalidKeyException e)
- {
- throw new CRMFException("key invalid in message.", e);
- }
- catch (IllegalBlockSizeException e)
- {
- throw new CRMFException("illegal blocksize in message.", e);
+ return new SecretKeySpec((byte[])unwrapper.generateUnwrappedKey(contentEncryptionAlgorithm, encryptedContentEncryptionKey).getRepresentation(), contentEncryptionAlgorithm.getAlgorithm().getId());
}
- catch (BadPaddingException e)
+ catch (OperatorException e)
{
- throw new CRMFException("bad padding in message.", e);
+ throw new CRMFException("key invalid in message: " + e.getMessage(), e);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/crmf/test/AllTests.java b/bcpkix/src/main/java/org/bouncycastle/cert/crmf/test/AllTests.java
index 837ddd03..2173a92e 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/crmf/test/AllTests.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/crmf/test/AllTests.java
@@ -9,24 +9,34 @@ import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
+import java.security.Signature;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
+import java.security.spec.MGF1ParameterSpec;
import java.util.Date;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
import javax.security.auth.x500.X500Principal;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
+import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers;
import org.bouncycastle.asn1.crmf.EncKeyWithID;
import org.bouncycastle.asn1.crmf.EncryptedValue;
+import org.bouncycastle.asn1.crmf.POPOSigningKey;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
@@ -103,6 +113,40 @@ public class AllTests
}
+ public void testBasicMessage()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setSubject(new X500Principal("CN=Test"))
+ .setPublicKey(kp.getPublic())
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build()).setProvider(BC);
+
+
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(certReqMsg.toASN1Structure().getPopo().getObject());
+
+ Signature sig = Signature.getInstance("SHA1withRSA", "BC");
+
+ sig.initVerify(certReqMsg.getPublicKey());
+
+ // this is the original approach in RFC 2511 - there's a typo in RFC 4211, the standard contradicts itself
+ // between 4.1. 3 and then a couple of paragraphs later.
+ sig.update(certReqMsg.toASN1Structure().getCertReq().getEncoded(ASN1Encoding.DER));
+
+ TestCase.assertTrue(sig.verify(popoSign.getSignature().getOctets()));
+
+ TestCase.assertEquals(new X500Principal("CN=Test"), certReqMsg.getSubjectX500Principal());
+ TestCase.assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
public void testBasicMessageWithArchiveControl()
throws Exception
{
@@ -325,6 +369,65 @@ public class AllTests
encryptedValueParserTest(EncryptedValue.getInstance(value.getEncoded()), decGen, cert);
}
+ public void testEncryptedValueOAEP1()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(2048);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ AlgorithmIdentifier sha256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+
+ JcaEncryptedValueBuilder build = new JcaEncryptedValueBuilder(new JceAsymmetricKeyWrapper(
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP,
+ new RSAESOAEPparams(sha256, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, sha256),
+ RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM)),
+ cert.getPublicKey()).setProvider(BC),
+ new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ EncryptedValue value = build.build(cert);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValueParserTest(value, decGen, cert);
+
+ // try indirect
+ encryptedValueParserTest(EncryptedValue.getInstance(value.getEncoded()), decGen, cert);
+ }
+
+ public void testEncryptedValueOAEP2()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(2048);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaEncryptedValueBuilder build = new JcaEncryptedValueBuilder(new JceAsymmetricKeyWrapper(
+ new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), new PSource.PSpecified(new byte[2])),
+ cert.getPublicKey()).setProvider(BC),
+ new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ EncryptedValue value = build.build(cert);
+
+ Assert.assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, value.getKeyAlg().getAlgorithm());
+ Assert.assertEquals(NISTObjectIdentifiers.id_sha256, RSAESOAEPparams.getInstance(value.getKeyAlg().getParameters()).getHashAlgorithm().getAlgorithm());
+ Assert.assertEquals(new DEROctetString(new byte[2]), RSAESOAEPparams.getInstance(value.getKeyAlg().getParameters()).getPSourceAlgorithm().getParameters());
+
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValueParserTest(value, decGen, cert);
+
+ // try indirect
+ encryptedValueParserTest(EncryptedValue.getInstance(value.getEncoded()), decGen, cert);
+ }
+
private void encryptedValueParserTest(EncryptedValue value, ValueDecryptorGenerator decGen, X509Certificate cert)
throws Exception
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java
index 28b39ffb..8d6e4e05 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntry.java
@@ -10,6 +10,11 @@ import org.bouncycastle.util.Arrays;
*/
public class DANEEntry
{
+ public static final int CERT_USAGE_CA = 0;
+ public static final int CERT_USAGE_PKIX_VALIDATE = 1;
+ public static final int CERT_USAGE_TRUST_ANCHOR = 2;
+ public static final int CERT_USAGE_ACCEPT = 3;
+
static final int CERT_USAGE = 0;
static final int SELECTOR = 1;
static final int MATCHING_TYPE = 2;
@@ -78,6 +83,6 @@ public class DANEEntry
public static boolean isValidCertificate(byte[] data)
{
// TODO: perhaps validate ASN.1 data as well...
- return (data[CERT_USAGE] == 3 && data[SELECTOR] == 0 && data[MATCHING_TYPE] == 0);
+ return ((data[CERT_USAGE] >= 0 || data[CERT_USAGE] <= 3)&& data[SELECTOR] == 0 && data[MATCHING_TYPE] == 0);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java
index 82465942..cf4e074f 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntryFactory.java
@@ -22,6 +22,7 @@ public class DANEEntryFactory
/**
* Return a DANEEntry for the passed in email address and certificate.
+ * This method sets the entry's certificate usage field to 3.
*
* @param emailAddress the emails address of interest.
* @param certificate the certificate to be associated with the email address.
@@ -30,10 +31,29 @@ public class DANEEntryFactory
public DANEEntry createEntry(String emailAddress, X509CertificateHolder certificate)
throws DANEException
{
+ return createEntry(emailAddress, DANEEntry.CERT_USAGE_ACCEPT, certificate);
+ }
+
+ /**
+ * Return a DANEEntry for the passed in email address and certificate.
+ *
+ * @param emailAddress the emails address of interest.
+ * @param certUsage the certificate usage field value to use.
+ * @param certificate the certificate to be associated with the email address.
+ * @throws DANEException in case of issue generating a matching name.
+ */
+ public DANEEntry createEntry(String emailAddress, int certUsage, X509CertificateHolder certificate)
+ throws DANEException
+ {
+ if (certUsage < 0 || certUsage > 3)
+ {
+ throw new DANEException("unknown certificate usage: " + certUsage);
+ }
+
DANEEntrySelector entrySelector = selectorFactory.createSelector(emailAddress);
byte[] flags = new byte[3];
- flags[DANEEntry.CERT_USAGE] = 3;
+ flags[DANEEntry.CERT_USAGE] = (byte)certUsage;
flags[DANEEntry.SELECTOR] = 0;
flags[DANEEntry.MATCHING_TYPE] = 0;
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntrySelectorFactory.java b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntrySelectorFactory.java
index 267e8d88..577ea224 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntrySelectorFactory.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/dane/DANEEntrySelectorFactory.java
@@ -16,8 +16,15 @@ public class DANEEntrySelectorFactory
/**
* Base constructor.
+ * <p>
+ * At the moment you would call this as:
+ * <pre>
+ * new DANEEntrySelectorFactory(new TruncatingDigestCalculator(new SHA256DigestCalculator()));
+ * </pre>
+ * or some equivalent.
+ * </p>
*
- * @param digestCalculator a calculator for the message digest to filter email addresses currently SHA-224.
+ * @param digestCalculator a calculator for the message digest to filter email addresses currently truncated SHA-256 (originally SHA-224).
*/
public DANEEntrySelectorFactory(DigestCalculator digestCalculator)
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/dane/TruncatingDigestCalculator.java b/bcpkix/src/main/java/org/bouncycastle/cert/dane/TruncatingDigestCalculator.java
new file mode 100644
index 00000000..f9a5382e
--- /dev/null
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/dane/TruncatingDigestCalculator.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.cert.dane;
+
+import java.io.OutputStream;
+
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.operator.DigestCalculator;
+
+/**
+ * A calculator which produces a truncated digest from a regular one, with the truncation
+ * achieved by dropping off the right most octets.
+ */
+public class TruncatingDigestCalculator
+ implements DigestCalculator
+{
+ private final DigestCalculator baseCalculator;
+ private final int length;
+
+ /**
+ * Default constructor - truncate to 28.
+ *
+ * @param baseCalculator actual calculator for working out the digest.
+ */
+ public TruncatingDigestCalculator(DigestCalculator baseCalculator)
+ {
+ this(baseCalculator, 28);
+ }
+
+ /**
+ * Constructor specifying a length.
+ *
+ * @param baseCalculator actual calculator for working out the digest.
+ * @param length length in bytes of the final result.
+ */
+ public TruncatingDigestCalculator(DigestCalculator baseCalculator, int length)
+ {
+ this.baseCalculator = baseCalculator;
+ this.length = length;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return baseCalculator.getAlgorithmIdentifier();
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return baseCalculator.getOutputStream();
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] rv = new byte[length];
+
+ byte[] dig = baseCalculator.getDigest();
+
+ System.arraycopy(dig, 0, rv, 0, rv.length);
+
+ return rv;
+ }
+}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java b/bcpkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java
index 74e08204..fa0d4624 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java
@@ -26,7 +26,7 @@ import org.bouncycastle.cert.dane.DANEException;
public class JndiDANEFetcherFactory
implements DANEEntryFetcherFactory
{
- private static final String DANE_TYPE = "65500";
+ private static final String DANE_TYPE = "53";
private List dnsServerList = new ArrayList();
private boolean isAuthoritative;
@@ -45,7 +45,7 @@ public class JndiDANEFetcherFactory
}
/**
- * Specify requests must be authoritative.
+ * Specify requests must be authoritative, or not (default false).
*
* @param isAuthoritative true if requests must be authoritative, false otherwise.
* @return the current factory..
@@ -100,27 +100,13 @@ public class JndiDANEFetcherFactory
NamingEnumeration bindings;
if (domainName.indexOf("_smimecert.") > 0)
{
- bindings = ctx.listBindings(domainName);
-
// need to use fully qualified domain name if using named DNS server.
Attributes attrs = ctx.getAttributes(domainName, new String[]{DANE_TYPE});
Attribute smimeAttr = attrs.get(DANE_TYPE);
if (smimeAttr != null)
{
- byte[] data = (byte[])attrs.get(DANE_TYPE).get();
-
- if (DANEEntry.isValidCertificate(data))
- {
- try
- {
- entries.add(new DANEEntry(domainName, data));
- }
- catch (IOException e)
- {
- throw new DANEException("Exception parsing entry: " + e.getMessage(), e);
- }
- }
+ addEntries(entries, domainName, smimeAttr);
}
}
else
@@ -141,25 +127,14 @@ public class JndiDANEFetcherFactory
if (smimeAttr != null)
{
- byte[] data = (byte[])attrs.get(DANE_TYPE).get();
-
- if (DANEEntry.isValidCertificate(data))
- {
- try
- {
- String fullName = sc.getNameInNamespace();
-
- entries.add(new DANEEntry(fullName.substring(1, fullName.length() - 1), data));
- }
- catch (IOException e)
- {
- throw new DANEException("Exception parsing entry: " + e.getMessage(), e);
- }
- }
+ String fullName = sc.getNameInNamespace();
+ String domainName = fullName.substring(1, fullName.length() - 1);
+
+ addEntries(entries, domainName, smimeAttr);
}
}
}
- ;
+
return entries;
}
catch (NamingException e)
@@ -169,4 +144,25 @@ public class JndiDANEFetcherFactory
}
};
}
+
+ private void addEntries(List entries, String domainName, Attribute smimeAttr)
+ throws NamingException, DANEException
+ {
+ for (int index = 0; index != smimeAttr.size(); index++)
+ {
+ byte[] data = (byte[])smimeAttr.get(index);
+
+ if (DANEEntry.isValidCertificate(data))
+ {
+ try
+ {
+ entries.add(new DANEEntry(domainName, data));
+ }
+ catch (IOException e)
+ {
+ throw new DANEException("Exception parsing entry: " + e.getMessage(), e);
+ }
+ }
+ }
+ }
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java b/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java
index b0cfb9ef..3f3c954a 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java
@@ -75,9 +75,9 @@ public class OCSPReqBuilder
}
/**
- * Set the requestor name to the passed in X500Principal
+ * Set the requestor name to the passed in X500Name
*
- * @param requestorName a X500Principal representing the requestor name.
+ * @param requestorName an X500Name representing the requestor name.
*/
public OCSPReqBuilder setRequestorName(
X500Name requestorName)
@@ -176,7 +176,7 @@ public class OCSPReqBuilder
* Generate an unsigned request
*
* @return the OCSPReq
- * @throws org.bouncycastle.ocsp.OCSPException
+ * @throws org.bouncycastle.cert.ocsp.OCSPException
*/
public OCSPReq build()
throws OCSPException
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java b/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java
index a0fd765a..4cd19ef9 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java
@@ -48,7 +48,7 @@ public class RespID
{
if (!digCalc.getAlgorithmIdentifier().equals(HASH_SHA1))
{
- throw new IllegalArgumentException("only SHA-1 can be used with RespID");
+ throw new IllegalArgumentException("only SHA-1 can be used with RespID - found: " + digCalc.getAlgorithmIdentifier().getAlgorithm());
}
OutputStream digOut = digCalc.getOutputStream();
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/path/test/CertPathValidationTest.java b/bcpkix/src/main/java/org/bouncycastle/cert/path/test/CertPathValidationTest.java
index a99cb1c4..80da034b 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/path/test/CertPathValidationTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/path/test/CertPathValidationTest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.cert.path.test;
import java.security.Security;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import org.bouncycastle.asn1.x509.Extension;
@@ -11,6 +12,7 @@ import org.bouncycastle.cert.X509ContentVerifierProviderBuilder;
import org.bouncycastle.cert.jcajce.JcaX509ContentVerifierProviderBuilder;
import org.bouncycastle.cert.path.CertPath;
import org.bouncycastle.cert.path.CertPathValidation;
+import org.bouncycastle.cert.path.CertPathValidationContext;
import org.bouncycastle.cert.path.CertPathValidationResult;
import org.bouncycastle.cert.path.validations.BasicConstraintsValidation;
import org.bouncycastle.cert.path.validations.CRLValidation;
@@ -233,9 +235,19 @@ public class CertPathValidationTest
// PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)cpv.validate(cp, param);
// }
+ private void basicConstraintsTest()
+ throws Exception
+ {
+ byte[] cert = Base64.decode("MIIDRzCCAi+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3QgQW5jaG9yMB4XDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowRTELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDFRydXN0IEFuY2hvcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALmZUYkRR+DNRbmEJ4ITAhbNRDmqrNsJw97iLE7bpFeflDUoNcJrZPZbC208bG+g5M0ATzV0vOqg88Ds1/FjFDK1oPItqsiDImJIq0xb/et5w72WNPxHVrcsr7Ap6DHfdwLpNMncqtzX92hU/iGVHLE/w/OCWwAIIbTHaxdrGMUG7DkJJ6iI7mzqpcyPvyAAo9O3SHjJr+uw5vSrHRretnV2un0bohvGslN64MY/UIiRnPFwd2gD76byDzoM1ioyLRCllfBJ5sRDz9xrUHNigTAUdlblb6yrnNtNJmkrROYvkh6sLETUh9EYh0Ar+94fZVXfGVi57Sw7x1jyANTlA40CAwEAAaNCMEAwHQYDVR0OBBYEFOR9X9FclYYILAWuvnW2ZafZXahmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCYoa9uR55KJTkpwyPihIgXHq7/Z8dx3qZlCJQwE5qQBZXIsf5eC8Va/QjnTHOC4Gt4MwpnqqmoDqyqSW8pBVQgAUFAXqO91nLCQb4+/yfjiiNjzprpxQlcqIZYjJSVtckH1IDWFLFeuGW+OgPPEFgN4hjU5YFIsE2r1i4+ixkeuorxxsK1D/jYbVwQMXLqn1pjJttOPJwuA8+ho1f2c8FrKlqjHgOwxuHhsiGN6MKgs1baalpR/lnNFCIpq+/+3cnhufDjvxMy5lg+cwgMCiGzCxn4n4dBMw41C+4KhNF7ZtKuKSZ1eczztXD9NUkGUGw3LzpLDJazz3JhlZ/9pXzF");
+
+ new BasicConstraintsValidation(true).validate(new CertPathValidationContext(new HashSet()), new X509CertificateHolder(cert));
+ }
+
public void performTest()
throws Exception
{
+ basicConstraintsTest();
+
// initialise CertStore
X509CertificateHolder rootCert = new X509CertificateHolder(CertPathTest.rootCertBin);
X509CertificateHolder interCert = new X509CertificateHolder(CertPathTest.interCertBin);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java b/bcpkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java
index db4f8527..bf67a820 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java
@@ -15,7 +15,8 @@ public class BasicConstraintsValidation
{
private boolean isMandatory;
private BasicConstraints bc;
- private int maxPathLength;
+ private int pathLengthRemaining;
+ private BigInteger maxPathLength;
public BasicConstraintsValidation()
{
@@ -30,7 +31,7 @@ public class BasicConstraintsValidation
public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
throws CertPathValidationException
{
- if (maxPathLength < 0)
+ if (maxPathLength != null && pathLengthRemaining < 0)
{
throw new CertPathValidationException("BasicConstraints path length exceeded");
}
@@ -51,9 +52,9 @@ public class BasicConstraintsValidation
{
int plc = pathLengthConstraint.intValue();
- if (plc < maxPathLength)
+ if (plc < pathLengthRemaining)
{
- maxPathLength = plc;
+ pathLengthRemaining = plc;
bc = certBC;
}
}
@@ -64,7 +65,12 @@ public class BasicConstraintsValidation
bc = certBC;
if (certBC.isCA())
{
- maxPathLength = certBC.getPathLenConstraint().intValue();
+ maxPathLength = certBC.getPathLenConstraint();
+
+ if (maxPathLength != null)
+ {
+ pathLengthRemaining = maxPathLength.intValue();
+ }
}
}
}
@@ -72,7 +78,7 @@ public class BasicConstraintsValidation
{
if (bc != null)
{
- maxPathLength--;
+ pathLengthRemaining--;
}
}
@@ -87,7 +93,7 @@ public class BasicConstraintsValidation
BasicConstraintsValidation v = new BasicConstraintsValidation(isMandatory);
v.bc = this.bc;
- v.maxPathLength = this.maxPathLength;
+ v.pathLengthRemaining = this.pathLengthRemaining;
return v;
}
@@ -98,6 +104,6 @@ public class BasicConstraintsValidation
this.isMandatory = v.isMandatory;
this.bc = v.bc;
- this.maxPathLength = v.maxPathLength;
+ this.pathLengthRemaining = v.pathLengthRemaining;
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/test/CertTest.java b/bcpkix/src/main/java/org/bouncycastle/cert/test/CertTest.java
index 71807406..9706af21 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/test/CertTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/test/CertTest.java
@@ -43,6 +43,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.x500.X500Name;
@@ -93,6 +94,8 @@ import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
@@ -1156,6 +1159,31 @@ public class CertTest
"D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
"vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+ private final byte[] sha3Cert = Base64.decode(
+ "MIID8jCCAqagAwIBAgIICfBykpzUT+IwQQYJKoZIhvcNAQEKMDSgDzANBglg"
+ + "hkgBZQMEAggFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEg"
+ + "MCwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNB"
+ + "MTAeFw0xNjEwMTgxODQzMjhaFw0yNjEwMTgxODQzMjdaMCwxCzAJBgNVBAYT"
+ + "AkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNBMTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAK/pzm1RASDYDg3WBXyW3AnAESRF/+li"
+ + "qh0X8Y89m+JFJeOi1u89bOSPjsFfo5SbRSElyRXedh/d37KrONg39NEKIcC6"
+ + "iSuiNfXu0D6nlSzhrQzmvHIyfLnm8N2JtHDr/hZIprOcFO+lZTJIjjrOVe9y"
+ + "lFGgGDd/uQCEJk1Cmi5Ivi9odeiN3z8lVlGNeN9/Q5n47ijuYWr73z/FyyAK"
+ + "gAG3B5nhAYWs4ft0O3JWBc0QJZzShqsRjm3SNhAqMDnRoTq04PFgbDYizV8T"
+ + "ydz2kCne79TDwsY4MckYYaGoNcPoQXVS+9YjQjI72ktSlxiJxodL9WMFl+ED"
+ + "5ZLBRIRsDJECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MGoGCCsGAQUF"
+ + "BwEBBF4wXDAnBggrBgEFBQcwAoYbaHR0cDovL2V4YW1wbGUub3JnL1JDQTEu"
+ + "ZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vbG9jYWxob3N0OjgwODAvb2NzcC9y"
+ + "ZXNwb25kZXIxMB0GA1UdDgQWBBRTXKdJI3P1kveLlRxPvzUfDnC8JjAOBgNV"
+ + "HQ8BAf8EBAMCAQYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAggFAKEc"
+ + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEgA4IBAQCpSVaqOMKz"
+ + "6NT0+mivEhig9cKsglFhnWStKUtdhrG4HqOf6Qjny9Xvq1nE7x8e2xAoaZLd"
+ + "GMsNAWFCbwzoJrDL7Ct6itQ5ymxi2haN+Urc5UWJd/8C0R74OdP1uPCiljZ9"
+ + "DdjbNk/hS36UPYi+FT5r6Jr/1X/EqgL1MOUsSTEXdYlZH662zjbV4D9QSBzx"
+ + "ul9bYyWrqSZFKvKef4UQwUy8yXtChwiwp50mfJQBdVcIqPBYCgmLYclamjQx"
+ + "hlkk5VbZb4D/Cv4HxrdxpJfy/ewUZR7uHlzDx0/m4qjzNzWgq+sh3ZbveDrV"
+ + "wd/FDMFOxSIno9qgHtdfgXRwZJ+l07fF");
+
private PublicKey dudPublicKey = new PublicKey()
{
public String getAlgorithm()
@@ -1283,7 +1311,9 @@ public class CertTest
PublicKey k = cert.getPublicKey();
- cert.verify(k);
+ X509CertificateHolder certHldr = new X509CertificateHolder(bytes);
+
+ certHldr.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(k));
// System.out.println(cert);
}
catch (Exception e)
@@ -2384,20 +2414,85 @@ public class CertTest
{
// expected
}
+ }
-// try
-// {
-// certGen.setPublicKey(dudPublicKey);
-//
-// certGen.generate(privKey, BC);
-//
-// fail("key without encoding not detected in v3");
-// }
-// catch (IllegalArgumentException e)
-// {
-// // expected
-// }
+ public void checkCreation6()
+ throws Exception
+ {
+ if (Security.getProvider("BCPQC") == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpGen.initialize(new SPHINCS256KeyGenParameterSpec(), new SecureRandom());
+
+ KeyPair kp = kpGen.generateKeyPair();
+
+ PrivateKey privKey = kp.getPrivate();
+ PublicKey pubKey = kp.getPublic();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA512withSPHINCS256").setProvider("BCPQC").build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ isTrue("oid wrong", BCObjectIdentifiers.sphincs256_with_SHA512.getId().equals(baseCert.getSigAlgOID()));
+ isTrue("params wrong", null == baseCert.getSigAlgParams());
+
+ //
+ // copy certificate
+ //
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey, "BCPQC");
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.15"), cert.getExtensionValue("2.5.29.15")))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.37"), cert.getExtensionValue("2.5.29.37")))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, new JcaX509CertificateHolder(baseCert));
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
}
private void testForgedSignature()
@@ -2977,7 +3072,8 @@ public class CertTest
checkSelfSignedCertificate(15, gost34102001base);
checkSelfSignedCertificate(16, gost341094A);
checkSelfSignedCertificate(17, gost341094B);
- checkSelfSignedCertificate(17, gost34102001A);
+ checkSelfSignedCertificate(18, gost34102001A);
+ checkSelfSignedCertificate(19, sha3Cert);
checkCRL(1, crl1);
@@ -2987,6 +3083,8 @@ public class CertTest
checkCreation4();
checkCreation5();
+ checkCreation6();
+
createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
createECCert("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
createECCert("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/test/DANETest.java b/bcpkix/src/main/java/org/bouncycastle/cert/test/DANETest.java
index 93954408..28aa4dc4 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/test/DANETest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/test/DANETest.java
@@ -7,6 +7,7 @@ import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.dane.DANEEntry;
import org.bouncycastle.cert.dane.DANEEntryFactory;
import org.bouncycastle.cert.dane.DANEException;
+import org.bouncycastle.cert.dane.TruncatingDigestCalculator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;
@@ -44,7 +45,7 @@ public class DANETest
private void shouldCreateDANEEntry()
throws IOException, DANEException
{
- DANEEntryFactory daneEntryFactory = new DANEEntryFactory(new SHA224DigestCalculator());
+ DANEEntryFactory daneEntryFactory = new DANEEntryFactory(new TruncatingDigestCalculator(new SHA256DigestCalculator()));
DANEEntry entry = daneEntryFactory.createEntry("test@test.com", new X509CertificateHolder(randomCert));
@@ -53,7 +54,7 @@ public class DANETest
fail("encoding error in RDATA");
}
- if (!"90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809._smimecert.test.com".equals(entry.getDomainName()))
+ if (!"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15._smimecert.test.com".equals(entry.getDomainName()))
{
fail("domain name associated with entry wrong");
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cert/test/SHA224DigestCalculator.java b/bcpkix/src/main/java/org/bouncycastle/cert/test/SHA256DigestCalculator.java
index f0de82e9..69dc235b 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cert/test/SHA224DigestCalculator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cert/test/SHA256DigestCalculator.java
@@ -6,18 +6,18 @@ import java.io.OutputStream;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.operator.DigestCalculator;
-class SHA224DigestCalculator
+class SHA256DigestCalculator
implements DigestCalculator
{
private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
public AlgorithmIdentifier getAlgorithmIdentifier()
{
- return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224);
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
}
public OutputStream getOutputStream()
@@ -31,13 +31,13 @@ class SHA224DigestCalculator
bOut.reset();
- Digest sha224 = new SHA224Digest();
+ Digest sha256 = new SHA256Digest();
- sha224.update(bytes, 0, bytes.length);
+ sha256.update(bytes, 0, bytes.length);
- byte[] digest = new byte[sha224.getDigestSize()];
+ byte[] digest = new byte[sha256.getDigestSize()];
- sha224.doFinal(digest, 0);
+ sha256.doFinal(digest, 0);
return digest;
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java
index f256e2a2..242d64bb 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java
@@ -17,7 +17,7 @@ public class CMSAbsentContent
public CMSAbsentContent()
{
- this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()));
+ this(CMSObjectIdentifiers.data);
}
public CMSAbsentContent(
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
index 7797f79f..f38d5c53 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
@@ -20,10 +20,6 @@ public class DefaultCMSSignatureEncryptionAlgorithmFinder
RSA_PKCS1d5.add(PKCSObjectIdentifiers.md4WithRSAEncryption);
RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption);
RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
- RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
- RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
- RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
- RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSAEncryption);
RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSA);
RSA_PKCS1d5.add(OIWObjectIdentifiers.md5WithRSA);
@@ -35,7 +31,7 @@ public class DefaultCMSSignatureEncryptionAlgorithmFinder
public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm)
{
- // RFC3370 section 3.2
+ // RFC3370 section 3.2 with RFC 5754 update
if (RSA_PKCS1d5.contains(signatureAlgorithm.getAlgorithm()))
{
return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
index ddfd2ebd..fb268b29 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
@@ -51,8 +51,8 @@ public class DefaultSignedAttributeTableGenerator
/**
* Create a standard attribute table from the passed in parameters - this will
- * normally include contentType, signingTime, and messageDigest. If the constructor
- * using an AttributeTable was used, entries in it for contentType, signingTime, and
+ * normally include contentType, signingTime, messageDigest, and CMS algorithm protection.
+ * If the constructor using an AttributeTable was used, entries in it for contentType, signingTime, and
* messageDigest will override the generated ones.
*
* @param parameters source parameters for table generation.
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java b/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java
index 7322fdcc..932c2762 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java
@@ -1,5 +1,7 @@
package org.bouncycastle.cms;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
public interface PasswordRecipient
@@ -8,6 +10,34 @@ public interface PasswordRecipient
public static final int PKCS5_SCHEME2 = 0;
public static final int PKCS5_SCHEME2_UTF8 = 1;
+ static final class PRF
+ {
+ public static final PRF HMacSHA1 = new PRF("HMacSHA1", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE));
+ public static final PRF HMacSHA224 = new PRF("HMacSHA224", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA224, DERNull.INSTANCE));
+ public static final PRF HMacSHA256 = new PRF("HMacSHA256", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256, DERNull.INSTANCE));
+ public static final PRF HMacSHA384 = new PRF("HMacSHA384", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA384, DERNull.INSTANCE));
+ public static final PRF HMacSHA512 = new PRF("HMacSHA512", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE));
+
+ private final String hmac;
+ final AlgorithmIdentifier prfAlgID;
+
+ private PRF(String hmac, AlgorithmIdentifier prfAlgID)
+ {
+ this.hmac = hmac;
+ this.prfAlgID = prfAlgID;
+ }
+
+ public String getName()
+ {
+ return hmac;
+ }
+
+ public AlgorithmIdentifier getAlgorithmID()
+ {
+ return prfAlgID;
+ }
+ }
+
byte[] calculateDerivedKey(int schemeID, AlgorithmIdentifier derivationAlgorithm, int keySize)
throws CMSException;
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java
index 5c99e596..f9d996a8 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java
@@ -13,6 +13,7 @@ import org.bouncycastle.asn1.pkcs.PBKDF2Params;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.GenericKey;
+import org.bouncycastle.util.Arrays;
public abstract class PasswordRecipientInfoGenerator
implements RecipientInfoGenerator
@@ -25,6 +26,9 @@ public abstract class PasswordRecipientInfoGenerator
private int schemeID;
private int keySize;
private int blockSize;
+ private PasswordRecipient.PRF prf;
+ private byte[] salt;
+ private int iterationCount;
protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password)
{
@@ -38,6 +42,8 @@ public abstract class PasswordRecipientInfoGenerator
this.kekAlgorithm = kekAlgorithm;
this.keySize = keySize;
this.blockSize = blockSize;
+ this.prf = PasswordRecipient.PRF.HMacSHA1;
+ this.iterationCount = 1024;
}
private static int getKeySize(ASN1ObjectIdentifier kekAlgorithm)
@@ -59,9 +65,17 @@ public abstract class PasswordRecipientInfoGenerator
return this;
}
+ public PasswordRecipientInfoGenerator setPRF(PasswordRecipient.PRF prf)
+ {
+ this.prf = prf;
+
+ return this;
+ }
+
public PasswordRecipientInfoGenerator setSaltAndIterationCount(byte[] salt, int iterationCount)
{
- this.keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount));
+ this.salt = Arrays.clone(salt);
+ this.iterationCount = iterationCount;
return this;
}
@@ -85,15 +99,15 @@ public abstract class PasswordRecipientInfoGenerator
random.nextBytes(iv);
- if (keyDerivationAlgorithm == null)
+ if (salt == null)
{
- byte[] salt = new byte[20];
+ salt = new byte[20];
random.nextBytes(salt);
-
- keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, 1024));
}
+ keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount, prf.prfAlgID));
+
byte[] derivedKey = calculateDerivedKey(schemeID, keyDerivationAlgorithm, keySize);
AlgorithmIdentifier kekAlgorithmId = new AlgorithmIdentifier(kekAlgorithm, new DEROctetString(iv));
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java
index 7a47a2f8..ccb6e2cf 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java
@@ -29,10 +29,11 @@ public class SignerInfoGeneratorBuilder
this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder());
}
- /**
- * Base constructor.
+ /**
+ * Base constructor with a particular finder for signature algorithms.
*
- * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ * @param sigEncAlgFinder finder for algorithm IDs to store for the signature encryption/signature algorithm field.
*/
public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java b/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java
index 56f2db64..5aca5268 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java
@@ -19,8 +19,9 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
public abstract class BcPasswordRecipient
implements PasswordRecipient
{
+ private final char[] password;
+
private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8;
- private char[] password;
BcPasswordRecipient(
char[] password)
@@ -58,11 +59,18 @@ public abstract class BcPasswordRecipient
PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters());
byte[] encodedPassword = (schemeID == PasswordRecipient.PKCS5_SCHEME2) ? PBEParametersGenerator.PKCS5PasswordToBytes(password) : PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password);
- PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
+ try
+ {
+ PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(EnvelopedDataHelper.getPRF(params.getPrf()));
- gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue());
+ gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue());
- return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("exception creating derived key: " + e.getMessage(), e);
+ }
}
public int getPasswordConversionScheme()
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java
index b279ce2c..48cdcbfb 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java
@@ -28,11 +28,18 @@ public class BcPasswordRecipientInfoGenerator
PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters());
byte[] encodedPassword = (schemeID == PasswordRecipient.PKCS5_SCHEME2) ? PBEParametersGenerator.PKCS5PasswordToBytes(password) : PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password);
- PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
-
- gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue());
-
- return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ try
+ {
+ PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(EnvelopedDataHelper.getPRF(params.getPrf()));
+
+ gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue());
+
+ return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("exception creating derived key: " + e.getMessage(), e);
+ }
}
public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey)
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java b/bcpkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java
index d04e9772..d2c3996c 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java
@@ -1,6 +1,7 @@
package org.bouncycastle.cms.bc;
import java.security.SecureRandom;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -25,9 +26,15 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.CAST5Engine;
import org.bouncycastle.crypto.engines.DESEngine;
@@ -43,12 +50,59 @@ import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.RC2Parameters;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.bc.BcDigestProvider;
class EnvelopedDataHelper
{
protected static final Map BASE_CIPHER_NAMES = new HashMap();
protected static final Map MAC_ALG_NAMES = new HashMap();
+ private static final Map prfs = createTable();
+
+ private static Map createTable()
+ {
+ Map table = new HashMap();
+
+ table.put(PKCSObjectIdentifiers.id_hmacWithSHA1, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA1Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.id_hmacWithSHA224, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA224Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.id_hmacWithSHA256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA256Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.id_hmacWithSHA384, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA384Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.id_hmacWithSHA512, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA512Digest();
+ }
+ });
+
+ return Collections.unmodifiableMap(table);
+ }
+
static
{
BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE");
@@ -117,6 +171,12 @@ class EnvelopedDataHelper
return name;
}
+ static ExtendedDigest getPRF(AlgorithmIdentifier algID)
+ throws OperatorCreationException
+ {
+ return ((BcDigestProvider)prfs.get(algID.getAlgorithm())).get(null);
+ }
+
static BufferedBlockCipher createCipher(ASN1ObjectIdentifier algorithm)
throws CMSException
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
index 5278b2eb..8cef68d7 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
@@ -58,6 +58,8 @@ public class EnvelopedDataHelper
protected static final Map CIPHER_ALG_NAMES = new HashMap();
protected static final Map MAC_ALG_NAMES = new HashMap();
+ private static final Map PBKDF2_ALG_NAMES = new HashMap();
+
static
{
BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_CBC, "DES");
@@ -92,6 +94,12 @@ public class EnvelopedDataHelper
MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac");
MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac");
MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac");
+
+ PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA1.getAlgorithmID(), "PBKDF2WITHHMACSHA1");
+ PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA224.getAlgorithmID(), "PBKDF2WITHHMACSHA224");
+ PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA256.getAlgorithmID(), "PBKDF2WITHHMACSHA256");
+ PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA384.getAlgorithmID(), "PBKDF2WITHHMACSHA384");
+ PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA512.getAlgorithmID(), "PBKDF2WITHHMACSHA512");
}
private static final short[] rc2Table = {
@@ -415,7 +423,7 @@ public class EnvelopedDataHelper
CMSUtils.loadParameters(params, sParams);
- mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
+ mac.init(sKey, params.getParameterSpec(AlgorithmParameterSpec.class));
}
catch (NoSuchAlgorithmException e)
{
@@ -690,7 +698,7 @@ public class EnvelopedDataHelper
}
else
{
- keyFact = helper.createSecretKeyFactory("PBKDF2");
+ keyFact = helper.createSecretKeyFactory((String)PBKDF2_ALG_NAMES.get(params.getPrf()));
}
SecretKey key = keyFact.generateSecret(new PBEKeySpec(password, params.getSalt(), params.getIterationCount().intValue(), keySize));
@@ -699,7 +707,7 @@ public class EnvelopedDataHelper
}
catch (GeneralSecurityException e)
{
- throw new CMSException("Unable to calculate dervied key from password: " + e.getMessage(), e);
+ throw new CMSException("Unable to calculate derived key from password: " + e.getMessage(), e);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java
index 8548ee6e..47db1caf 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java
@@ -10,7 +10,7 @@ import org.bouncycastle.operator.SymmetricKeyUnwrapper;
import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
import org.bouncycastle.operator.jcajce.JceKTSKeyUnwrapper;
-public interface JcaJceExtHelper
+interface JcaJceExtHelper
extends JcaJceHelper
{
JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java
index 4a0e7ca4..17a2f093 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java
@@ -6,6 +6,8 @@ import java.security.cert.X509Certificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.cms.CMSAttributeTableGenerator;
+import org.bouncycastle.cms.CMSSignatureEncryptionAlgorithmFinder;
+import org.bouncycastle.cms.DefaultCMSSignatureEncryptionAlgorithmFinder;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.SignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
@@ -16,9 +18,25 @@ public class JcaSignerInfoGeneratorBuilder
{
private SignerInfoGeneratorBuilder builder;
+ /**
+ * Base constructor.
+ *
+ * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ */
public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider)
{
- builder = new SignerInfoGeneratorBuilder(digestProvider);
+ this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder());
+ }
+
+ /**
+ * Base constructor with a particular finder for signature algorithms.
+ *
+ * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ * @param sigEncAlgFinder finder for algorithm IDs to store for the signature encryption/signature algorithm field.
+ */
+ public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
+ {
+ builder = new SignerInfoGeneratorBuilder(digestProvider, sigEncAlgFinder);
}
/**
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
index 379917be..93c216af 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
@@ -22,6 +22,9 @@ import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.operator.SecretKeySizeProvider;
import org.bouncycastle.operator.jcajce.JceGenericKey;
+/**
+ * Builder for the content encryptor in EnvelopedData - used to encrypt the actual transmitted content.
+ */
public class JceCMSContentEncryptorBuilder
{
private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
@@ -32,6 +35,7 @@ public class JceCMSContentEncryptorBuilder
private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
private SecureRandom random;
+ private AlgorithmParameters algorithmParameters;
public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
{
@@ -70,6 +74,12 @@ public class JceCMSContentEncryptorBuilder
}
}
+ /**
+ * Set the provider to use for content encryption.
+ *
+ * @param provider the provider object to use for cipher and default parameters creation.
+ * @return the current builder instance.
+ */
public JceCMSContentEncryptorBuilder setProvider(Provider provider)
{
this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
@@ -77,6 +87,12 @@ public class JceCMSContentEncryptorBuilder
return this;
}
+ /**
+ * Set the provider to use for content encryption (by name)
+ *
+ * @param providerName the name of the provider to use for cipher and default parameters creation.
+ * @return the current builder instance.
+ */
public JceCMSContentEncryptorBuilder setProvider(String providerName)
{
this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
@@ -84,6 +100,12 @@ public class JceCMSContentEncryptorBuilder
return this;
}
+ /**
+ * Provide a specified source of randomness to be used for session key and IV/nonce generation.
+ *
+ * @param random the secure random to use.
+ * @return the current builder instance.
+ */
public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
{
this.random = random;
@@ -91,10 +113,23 @@ public class JceCMSContentEncryptorBuilder
return this;
}
+ /**
+ * Provide a set of algorithm parameters for the content encryption cipher to use.
+ *
+ * @param algorithmParameters algorithmParameters for content encryption.
+ * @return the current builder instance.
+ */
+ public JceCMSContentEncryptorBuilder setAlgorithmParameters(AlgorithmParameters algorithmParameters)
+ {
+ this.algorithmParameters = algorithmParameters;
+
+ return this;
+ }
+
public OutputEncryptor build()
throws CMSException
{
- return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random);
}
private class CMSOutputEncryptor
@@ -104,7 +139,7 @@ public class JceCMSContentEncryptorBuilder
private AlgorithmIdentifier algorithmIdentifier;
private Cipher cipher;
- CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
throws CMSException
{
KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
@@ -125,7 +160,11 @@ public class JceCMSContentEncryptorBuilder
cipher = helper.createCipher(encryptionOID);
encKey = keyGen.generateKey();
- AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ if (params == null)
+ {
+ params = helper.generateParameters(encryptionOID, encKey, random);
+ }
try
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
index d6ba1609..4a334cc2 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
@@ -1,21 +1,15 @@
package org.bouncycastle.cms.jcajce;
import java.io.OutputStream;
-import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.RC2ParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.jcajce.io.MacOutputStream;
@@ -29,6 +23,7 @@ public class JceCMSMacCalculatorBuilder
private final int keySize;
private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private AlgorithmParameters algorithmParameters;
private SecureRandom random;
public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID)
@@ -42,6 +37,12 @@ public class JceCMSMacCalculatorBuilder
this.keySize = keySize;
}
+ /**
+ * Set the provider to use for content encryption.
+ *
+ * @param provider the provider object to use for MAC and default parameters creation.
+ * @return the current builder instance.
+ */
public JceCMSMacCalculatorBuilder setProvider(Provider provider)
{
this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
@@ -49,6 +50,12 @@ public class JceCMSMacCalculatorBuilder
return this;
}
+ /**
+ * Set the provider to use for content encryption (by name)
+ *
+ * @param providerName the name of the provider to use for MAC and default parameters creation.
+ * @return the current builder instance.
+ */
public JceCMSMacCalculatorBuilder setProvider(String providerName)
{
this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
@@ -56,6 +63,12 @@ public class JceCMSMacCalculatorBuilder
return this;
}
+ /**
+ * Provide a specified source of randomness to be used for session key and IV/nonce generation.
+ *
+ * @param random the secure random to use.
+ * @return the current builder instance.
+ */
public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random)
{
this.random = random;
@@ -63,10 +76,23 @@ public class JceCMSMacCalculatorBuilder
return this;
}
+ /**
+ * Provide a set of algorithm parameters for the content MAC calculator to use.
+ *
+ * @param algorithmParameters algorithmParameters for MAC initialisation.
+ * @return the current builder instance.
+ */
+ public JceCMSMacCalculatorBuilder setAlgorithmParameters(AlgorithmParameters algorithmParameters)
+ {
+ this.algorithmParameters = algorithmParameters;
+
+ return this;
+ }
+
public MacCalculator build()
throws CMSException
{
- return new CMSMacCalculator(macOID, keySize, random);
+ return new CMSMacCalculator(macOID, keySize, algorithmParameters, random);
}
private class CMSMacCalculator
@@ -75,9 +101,8 @@ public class JceCMSMacCalculatorBuilder
private SecretKey encKey;
private AlgorithmIdentifier algorithmIdentifier;
private Mac mac;
- private SecureRandom random;
- CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random)
+ CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, AlgorithmParameters params, SecureRandom random)
throws CMSException
{
KeyGenerator keyGen = helper.createKeyGenerator(macOID);
@@ -87,8 +112,6 @@ public class JceCMSMacCalculatorBuilder
random = new SecureRandom();
}
- this.random = random;
-
if (keySize < 0)
{
keyGen.init(random);
@@ -100,9 +123,12 @@ public class JceCMSMacCalculatorBuilder
encKey = keyGen.generateKey();
- AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey);
+ if (params == null)
+ {
+ params = helper.generateParameters(macOID, encKey, random);
+ }
- algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec);
+ algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, params);
mac = helper.createContentMac(encKey, algorithmIdentifier);
}
@@ -125,31 +151,5 @@ public class JceCMSMacCalculatorBuilder
{
return new JceGenericKey(algorithmIdentifier, encKey);
}
-
- protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey)
- throws CMSException
- {
- try
- {
- if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC))
- {
- byte[] iv = new byte[8];
-
- random.nextBytes(iv);
-
- return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv);
- }
-
- AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID);
-
- AlgorithmParameters p = pGen.generateParameters();
-
- return p.getParameterSpec(IvParameterSpec.class);
- }
- catch (GeneralSecurityException e)
- {
- return null;
- }
- }
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java
index a0222d2b..9f4f5917 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewAuthenticatedDataTest.java
@@ -1,5 +1,7 @@
package org.bouncycastle.cms.test;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
@@ -16,13 +18,18 @@ import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cms.AuthenticatedData;
+import org.bouncycastle.asn1.cms.CCMParameters;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSAlgorithm;
@@ -147,6 +154,9 @@ public class NewAuthenticatedDataTest
throws Exception
{
tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+
+ DEROctetString iv = new DEROctetString(Hex.decode("0001020304050607"));
+ tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"), iv.getEncoded());
}
public void testKEKDESedeWithDigest()
@@ -281,6 +291,53 @@ public class NewAuthenticatedDataTest
}
}
+ public void testAES256CCM()
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+ ASN1ObjectIdentifier macAlg = CMSAlgorithm.AES256_CCM;
+ AlgorithmParameters algParams = AlgorithmParameters.getInstance("CCM", BC);
+
+ algParams.init(new CCMParameters(Hex.decode("000102030405060708090a0b"), 16).getEncoded());
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ adGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(macAlg).setAlgorithmParameters(algParams).setProvider(BC).build());
+
+ assertTrue(ad.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertEquals(16, ad.getMac().length);
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
public void testCMSAlgorithmProtection()
throws Exception
{
@@ -480,6 +537,50 @@ public class NewAuthenticatedDataTest
}
}
+ private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid, byte[] encodedParameters)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, OperatorCreationException, IOException
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ byte[] kekId = new byte[]{1, 2, 3, 4, 5};
+
+ adGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ AlgorithmParameters algParams = AlgorithmParameters.getInstance(CMSAlgorithm.DES_EDE3_CBC.getId(), "BC");
+
+ algParams.init(encodedParameters);
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setAlgorithmParameters(algParams).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ad.getMacAlgOID(), CMSAuthenticatedDataGenerator.DES_EDE3_CBC);
+ assertEquals(ad.getMacAlgorithm().getParameters(), ASN1Primitive.fromByteArray(encodedParameters));
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), algOid.getId());
+
+ byte[] recData = recipient.getContent(new JceKEKAuthenticatedRecipient(kek).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
private void tryKekAlgorithmWithDigest(SecretKey kek, ASN1ObjectIdentifier algOid)
throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, OperatorCreationException
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
index 310ee01d..b2714574 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.cms.test;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
@@ -39,12 +40,15 @@ import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
+import org.bouncycastle.asn1.cms.CCMParameters;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.EncryptedContentInfo;
import org.bouncycastle.asn1.cms.EnvelopedData;
+import org.bouncycastle.asn1.cms.GCMParameters;
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.asn1.x500.X500Name;
@@ -69,6 +73,8 @@ import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.SimpleAttributeTableGenerator;
import org.bouncycastle.cms.bc.BcCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.bc.BcPasswordEnvelopedRecipient;
+import org.bouncycastle.cms.bc.BcPasswordRecipientInfoGenerator;
import org.bouncycastle.cms.bc.BcRSAKeyTransRecipientInfoGenerator;
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
import org.bouncycastle.cms.jcajce.JceKEKEnvelopedRecipient;
@@ -94,125 +100,125 @@ public class NewEnvelopedDataTest
extends TestCase
{
private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
-
- private static String _signDN;
- private static KeyPair _signKP;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
private static X509Certificate _signCert;
- private static String _origDN;
- private static KeyPair _origKP;
+ private static String _origDN;
+ private static KeyPair _origKP;
private static X509Certificate _origCert;
- private static String _reciDN;
- private static String _reciDN2;
- private static KeyPair _reciKP;
- private static KeyPair _reciOaepKP;
+ private static String _reciDN;
+ private static String _reciDN2;
+ private static KeyPair _reciKP;
+ private static KeyPair _reciOaepKP;
private static X509Certificate _reciCert;
private static X509Certificate _reciCertOaep;
- private static KeyPair _origEcKP;
- private static KeyPair _reciEcKP;
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
private static X509Certificate _reciEcCert;
- private static KeyPair _reciEcKP2;
+ private static KeyPair _reciEcKP2;
private static X509Certificate _reciEcCert2;
- private static KeyPair _reciKemsKP;
+ private static KeyPair _reciKemsKP;
private static X509Certificate _reciKemsCert;
- private static KeyPair _origDhKP;
- private static KeyPair _reciDhKP;
+ private static KeyPair _origDhKP;
+ private static KeyPair _reciDhKP;
private static X509Certificate _reciDhCert;
- private static boolean _initialised = false;
+ private static boolean _initialised = false;
private byte[] oldKEK = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
- + "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
- + "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
+ + "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
+ + "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
private byte[] ecKeyAgreeMsgAES256 = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
- + "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
- + "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
- + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
- + "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
- + "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
- + "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
+ + "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
+ + "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
+ + "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
+ + "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
private byte[] ecKeyAgreeMsgAES128 = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
- + "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
- + "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
- + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
- + "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
- + "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
- + "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
+ + "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
+ + "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
+ + "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
+ + "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
private byte[] ecKeyAgreeMsgDESEDE = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
- + "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
- + "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
- + "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
- + "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
- + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
- + "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
-
- private byte[] ecMQVKeyAgreeMsgAES128 = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
- + "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
- + "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
- + "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
- + "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
- + "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
- + "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
- + "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
- + "AAAAAAAAAAA=");
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
+ + "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
+ + "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
+ + "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
+ + "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
+
+ private byte[] ecMQVKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
+ + "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
+ + "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
+ + "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
+ + "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
+ + "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
+ + "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
+ + "AAAAAAAAAAA=");
private byte[] ecKeyAgreeKey = Base64.decode(
"MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8vp7xVTbKSgYVU5Wc"
- + "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
- + "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
- + "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
+ + "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
+ + "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
+ + "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
private byte[] bobPrivRsaEncrypt = Base64.decode(
- "MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
- + "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
- + "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
- + "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
- + "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
- + "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
- + "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
- + "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
- + "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
- + "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
- + "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
- + "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
- + "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
- + "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
- + "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
+ "MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
+ + "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
+ + "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
+ + "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
+ + "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
+ + "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
+ + "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
+ + "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
+ + "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
+ + "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
+ + "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
+ + "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
+ + "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
+ + "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
+ + "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
private byte[] rfc4134ex5_1 = Base64.decode(
- "MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
- + "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
- + "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
- + "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
- + "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
- + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
- + "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
+ "MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
+ + "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
+ + "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
+ + "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
+ + "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
+ + "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
private byte[] rfc4134ex5_2 = Base64.decode(
- "MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
- + "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
- + "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
- + "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
- + "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
- + "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
- + "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
- + "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
- + "yw==");
+ "MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
+ + "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
+ + "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
+ + "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
+ + "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
+ + "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
+ + "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
+ + "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
+ + "yw==");
private byte[] tooShort3DES = Base64.decode(
- "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKDA1C" +
+ "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKDA1C" +
"b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBCjANBgkqhkiG9w0BAQEFAASB" +
"gJIM2QN0o6iv8Ux018pVCJ8js+ROV4t6+KoMwLJ4DzRKLU8XCAb9BS+crP+F" +
"ghNTxTpTX8TaxPrO4wV0USgVHu2SvFnxNaWZjBDVIyZI2HR4QkSTqFMhsUB2" +
@@ -221,7 +227,7 @@ public class NewEnvelopedDataTest
"AAAAAAAA");
private byte[] tooShort3DESKey = Base64.decode(
- "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAODZDCj0nQdV" +
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAODZDCj0nQdV" +
"f0GGeFsPjjvPx1Vem0V6IkJ4SzazGKfddk0pX58ZDCnG+S+OPiXmPDqValiu" +
"9FtNy2/r9rrf/6qtcVQJkfSJv9E5Y7HgI98L/Y9lKxZWsfRqu/SlYO5zx0Dc" +
"2rzDvvZRtrtaq0uuHXWJlbWda2L9S65sv/Le/zvjAgMBAAECgYEAnn+iGMTG" +
@@ -255,17 +261,17 @@ public class NewEnvelopedDataTest
_initialised = true;
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
- _signDN = "O=Bouncy Castle, C=AU";
- _signKP = CMSTestUtil.makeKeyPair();
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
_signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
- _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
- _origKP = CMSTestUtil.makeKeyPair();
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
_origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
- _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
- _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
- _reciKP = CMSTestUtil.makeKeyPair();
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
_reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
_reciCertOaep = CMSTestUtil.makeOaepCertificate(_reciKP, _reciDN, _signKP, _signDN);
@@ -302,7 +308,7 @@ public class NewEnvelopedDataTest
public void testUnprotectedAttributes()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -318,10 +324,10 @@ public class NewEnvelopedDataTest
edGen.setUnprotectedAttributeGenerator(new SimpleAttributeTableGenerator(attrTable));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
@@ -331,16 +337,16 @@ public class NewEnvelopedDataTest
assertEquals(new DERUTF8String("Hint"), attrTable.get(PKCSObjectIdentifiers.id_aa_contentHint).getAttrValues().getObjectAt(0));
assertEquals(new DERUTF8String("Request"), attrTable.get(PKCSObjectIdentifiers.id_aa_receiptRequest).getAttrValues().getObjectAt(0));
-
- Collection c = recipients.getRecipients();
+
+ Collection c = recipients.getRecipients();
assertEquals(1, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
@@ -399,7 +405,7 @@ public class NewEnvelopedDataTest
public void testKeyTrans()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -407,23 +413,23 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(2, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
@@ -445,32 +451,32 @@ public class NewEnvelopedDataTest
public void testKeyTransOAEPDefault()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
- JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
+ JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert, paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT)).setProvider(BC));
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT), _reciCert.getPublicKey()).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(2, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
@@ -490,25 +496,25 @@ public class NewEnvelopedDataTest
}
public void testKeyTransOAEPSHA1()
- throws Exception
+ throws Exception
{
doTestKeyTransOAEPDefaultNamed("SHA-1");
}
public void testKeyTransOAEPSHA224()
- throws Exception
+ throws Exception
{
doTestKeyTransOAEPDefaultNamed("SHA-224");
}
public void testKeyTransOAEPSHA256()
- throws Exception
+ throws Exception
{
doTestKeyTransOAEPDefaultNamed("SHA-256");
}
public void testKeyTransOAEPSHA1AndSHA256()
- throws Exception
+ throws Exception
{
doTestKeyTransOAEPDefaultNamed("SHA-1", "SHA-256");
}
@@ -522,10 +528,10 @@ public class NewEnvelopedDataTest
private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest)
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
- JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
+ JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
OAEPParameterSpec oaepSpec = new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(mgfDigest), new PSource.PSpecified(new byte[]{1, 2, 3, 4, 5}));
AlgorithmIdentifier oaepAlgId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
@@ -534,23 +540,23 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), oaepAlgId, _reciCert.getPublicKey()).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(2, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
@@ -570,77 +576,77 @@ public class NewEnvelopedDataTest
}
public void testKeyTransOAEPInCert()
- throws Exception
- {
- byte[] data = "WallaWallaWashington".getBytes();
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
- CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
- edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCertOaep).setProvider(BC));
- edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCertOaep.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCertOaep.getPublicKey()).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCertOaep).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCertOaep.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCertOaep.getPublicKey()).setProvider(BC));
- CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
- assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
- assertEquals(2, c.size());
+ assertEquals(2, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
- while (it.hasNext())
- {
- RecipientInformation recipient = (RecipientInformation)it.next();
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
- assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
+ assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
- byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
- assertEquals(true, Arrays.equals(data, recData));
- }
+ assertEquals(true, Arrays.equals(data, recData));
+ }
- RecipientId id = new JceKeyTransRecipientId(_reciCertOaep);
+ RecipientId id = new JceKeyTransRecipientId(_reciCertOaep);
- Collection collection = recipients.getRecipients(id);
- if (collection.size() != 2)
- {
- fail("recipients not matched using general recipient ID.");
- }
- assertTrue(collection.iterator().next() instanceof RecipientInformation);
- }
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
public void testKeyTransWithAlgMapping()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/2/PKCS1Padding").setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(1, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
@@ -662,7 +668,7 @@ public class NewEnvelopedDataTest
public void testOriginatorInfoGeneration()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -674,25 +680,25 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
assertTrue(ed.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(2, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
@@ -714,7 +720,7 @@ public class NewEnvelopedDataTest
public void testKeyTransRC2bit40()
throws Exception
{
- byte[] data = "WallaWallaBouncyCastle".getBytes();
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -724,22 +730,22 @@ public class NewEnvelopedDataTest
new CMSProcessableByteArray(data),
new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getContentEncryptionAlgorithm().getAlgorithm(), CMSAlgorithm.RC2_CBC);
RC2CBCParameter rc2P = RC2CBCParameter.getInstance(ed.getContentEncryptionAlgorithm().getParameters());
assertEquals(160, rc2P.getRC2ParameterVersion().intValue());
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(1, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
@@ -750,29 +756,29 @@ public class NewEnvelopedDataTest
public void testKeyTransRC4()
throws Exception
{
- byte[] data = "WallaWallaBouncyCastle".getBytes();
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4")).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4")).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(1, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
@@ -783,26 +789,26 @@ public class NewEnvelopedDataTest
public void testKeyTrans128RC4()
throws Exception
{
- byte[] data = "WallaWallaBouncyCastle".getBytes();
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
@@ -817,26 +823,26 @@ public class NewEnvelopedDataTest
public void testKeyTransLight128RC4()
throws Exception
{
- byte[] data = "WallaWallaBouncyCastle".getBytes();
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
@@ -851,26 +857,26 @@ public class NewEnvelopedDataTest
public void testKeyTransODES()
throws Exception
{
- byte[] data = "WallaWallaBouncyCastle".getBytes();
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.3.14.3.2.7")).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.3.14.3.2.7")).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), "1.3.14.3.2.7");
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
@@ -885,27 +891,27 @@ public class NewEnvelopedDataTest
public void testKeyTransSmallAES()
throws Exception
{
- byte[] data = new byte[] { 0, 1, 2, 3 };
+ byte[] data = new byte[]{0, 1, 2, 3};
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(),
- CMSEnvelopedDataGenerator.AES128_CBC);
+ CMSEnvelopedDataGenerator.AES128_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
assertEquals(true, Arrays.equals(data, recData));
@@ -919,22 +925,22 @@ public class NewEnvelopedDataTest
public void testKeyTransDESEDE3Short()
throws Exception
{
- byte[] data = new byte[] { 0, 1, 2, 3 };
- KeyFactory kf = KeyFactory.getInstance("RSA", BC);
- PrivateKey kPriv = kf.generatePrivate(new PKCS8EncodedKeySpec(tooShort3DESKey));
+ byte[] data = new byte[]{0, 1, 2, 3};
+ KeyFactory kf = KeyFactory.getInstance("RSA", BC);
+ PrivateKey kPriv = kf.generatePrivate(new PKCS8EncodedKeySpec(tooShort3DESKey));
CMSEnvelopedData ed = new CMSEnvelopedData(tooShort3DES);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
try
{
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(kPriv).setKeySizeValidation(true).setProvider(BC));
@@ -957,26 +963,26 @@ public class NewEnvelopedDataTest
public void testKeyTransDESEDE3Light()
throws Exception
{
- byte[] data = new byte[] { 0, 1, 2, 3 };
+ byte[] data = new byte[]{0, 1, 2, 3};
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC, 192).build());
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC, 192).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setKeySizeValidation(true).setProvider(BC));
assertEquals(true, Arrays.equals(data, recData));
@@ -988,12 +994,12 @@ public class NewEnvelopedDataTest
}
public void testKeyTransDES()
- throws Exception
- {
- tryKeyTrans(CMSAlgorithm.DES_CBC, CMSAlgorithm.DES_CBC, 8, DEROctetString.class);
- }
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.DES_CBC, CMSAlgorithm.DES_CBC, 8, DEROctetString.class);
+ }
- public void testKeyTransCAST5()
+ public void testKeyTransCAST5()
throws Exception
{
tryKeyTrans(CMSAlgorithm.CAST5_CBC, CMSAlgorithm.CAST5_CBC, 16, ASN1Sequence.class);
@@ -1044,7 +1050,7 @@ public class NewEnvelopedDataTest
private void tryKeyTrans(ASN1ObjectIdentifier generatorOID, ASN1ObjectIdentifier checkOID, int keySize, Class asn1Params)
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -1055,7 +1061,7 @@ public class NewEnvelopedDataTest
new CMSProcessableByteArray(data),
encryptor);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(checkOID.getId(), ed.getEncryptionAlgOID());
assertEquals(keySize, ((byte[])encryptor.getKey().getRepresentation()).length);
@@ -1067,11 +1073,11 @@ public class NewEnvelopedDataTest
assertTrue(asn1Params.isAssignableFrom(aIn.readObject().getClass()));
}
- Collection c = recipients.getRecipients();
+ Collection c = recipients.getRecipients();
assertEquals(1, c.size());
- Iterator it = c.iterator();
+ Iterator it = c.iterator();
if (!it.hasNext())
{
@@ -1080,7 +1086,7 @@ public class NewEnvelopedDataTest
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
@@ -1093,21 +1099,21 @@ public class NewEnvelopedDataTest
public void testErroneousKEK()
throws Exception
{
- byte[] data = "WallaWallaWashington".getBytes();
- SecretKey kek = new SecretKeySpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, "AES");
+ byte[] data = "WallaWallaWashington".getBytes();
+ SecretKey kek = new SecretKeySpec(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, "AES");
CMSEnvelopedData ed = new CMSEnvelopedData(oldKEK);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals(recipient.getKeyEncryptionAlgOID(), NISTObjectIdentifiers.id_aes128_wrap.getId());
@@ -1126,6 +1132,7 @@ public class NewEnvelopedDataTest
{
tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
}
+
public void testRC2128KEK()
throws Exception
{
@@ -1141,9 +1148,14 @@ public class NewEnvelopedDataTest
tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_GCM, NISTObjectIdentifiers.id_aes192_GCM);
tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_GCM, NISTObjectIdentifiers.id_aes256_GCM);
+ byte[] nonce = Hex.decode("0102030405060708090a0b0c");
+ tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_GCM, NISTObjectIdentifiers.id_aes128_GCM, new GCMParameters(nonce, 11).getEncoded());
+
tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, NISTObjectIdentifiers.id_aes128_CCM);
tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_CCM, NISTObjectIdentifiers.id_aes192_CCM);
tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_CCM, NISTObjectIdentifiers.id_aes256_CCM);
+
+ tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, NISTObjectIdentifiers.id_aes128_CCM, new CCMParameters(nonce, 13).getEncoded());
}
public void testAES192KEK()
@@ -1185,16 +1197,16 @@ public class NewEnvelopedDataTest
private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid)
throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
- byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+ byte[] kekId = new byte[]{1, 2, 3, 4, 5};
edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
RecipientInformationStore recipients = ed.getRecipientInfos();
@@ -1222,16 +1234,16 @@ public class NewEnvelopedDataTest
private void tryKekAlgorithmAEAD(SecretKey kek, ASN1ObjectIdentifier algOid, ASN1ObjectIdentifier aeadAlgorithm, ASN1ObjectIdentifier baseOID)
throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, IOException
{
- byte[] data = "WallaWallaWashington".getBytes();
+ byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
- byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+ byte[] kekId = new byte[]{1, 2, 3, 4, 5};
edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(aeadAlgorithm).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(aeadAlgorithm).setProvider(BC).build());
RecipientInformationStore recipients = ed.getRecipientInfos();
@@ -1255,9 +1267,60 @@ public class NewEnvelopedDataTest
fail("no recipient found");
}
- byte[] edData = ed.getEncoded();
+ checkAlteredMAC(kek, algOid, ed.getEncoded());
+ }
+
+ private void tryKekAlgorithmAEAD(SecretKey kek, ASN1ObjectIdentifier algOid, ASN1ObjectIdentifier aeadAlgorithm, ASN1ObjectIdentifier baseOID, byte[] encodedParameters)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, IOException
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ byte[] kekId = new byte[]{1, 2, 3, 4, 5};
+
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ AlgorithmParameters algParams = AlgorithmParameters.getInstance(aeadAlgorithm.getId(), BC);
+
+ algParams.init(encodedParameters);
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(aeadAlgorithm).setProvider(BC).setAlgorithmParameters(algParams).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ed.getContentEncryptionAlgorithm().getAlgorithm(), baseOID);
+ assertEquals(ed.getContentEncryptionAlgorithm().getParameters(), ASN1Sequence.getInstance(encodedParameters));
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
- ContentInfo eContentInfo = ContentInfo.getInstance(edData);
+ assertEquals(algOid.getId(), recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setKeySizeValidation(true).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ checkAlteredMAC(kek, algOid, ed.getEncoded());
+ }
+
+ private void checkAlteredMAC(SecretKey kek, ASN1ObjectIdentifier algOid, byte[] edData)
+ throws CMSException, IOException
+ {
+ CMSEnvelopedData ed;
+ RecipientInformationStore recipients;
+ Collection c;
+ Iterator it;ContentInfo eContentInfo = ContentInfo.getInstance(edData);
EnvelopedData envD = EnvelopedData.getInstance(eContentInfo.getContent());
@@ -1304,7 +1367,7 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF,
_origEcKP.getPrivate(), _origEcKP.getPublic(),
- CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
CMSEnvelopedData ed = edGen.generate(
new CMSProcessableByteArray(data),
@@ -1446,12 +1509,12 @@ public class NewEnvelopedDataTest
edGen = new CMSEnvelopedDataGenerator();
edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(PKCSObjectIdentifiers.id_alg_SSDH,
- _origDhKP.getPrivate(), _origDhKP.getPublic(),
- CMSAlgorithm.AES128_WRAP).addRecipient(_reciDhCert).setProvider(BC));
+ _origDhKP.getPrivate(), _origDhKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciDhCert).setProvider(BC));
edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
fail("no UKM uncaught");
}
catch (CMSException e)
@@ -1534,7 +1597,7 @@ public class NewEnvelopedDataTest
}
private static void confirmDataReceived(RecipientInformationStore recipients,
- byte[] expectedData, X509Certificate reciCert, PrivateKey reciPrivKey, String provider)
+ byte[] expectedData, X509Certificate reciCert, PrivateKey reciPrivKey, String provider)
throws CMSException, NoSuchProviderException, CertificateEncodingException, IOException
{
RecipientId rid = new JceKeyAgreeRecipientId(reciCert);
@@ -1555,8 +1618,8 @@ public class NewEnvelopedDataTest
throws Exception
{
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
- KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
- PrivateKey privKey = fact.generatePrivate(privSpec);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.42", ecKeyAgreeMsgAES256);
verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecKeyAgreeMsgAES128);
@@ -1567,8 +1630,8 @@ public class NewEnvelopedDataTest
throws Exception
{
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
- KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
- PrivateKey privKey = fact.generatePrivate(privSpec);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
verifyECMQVKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecMQVKeyAgreeMsgAES128);
}
@@ -1587,6 +1650,57 @@ public class NewEnvelopedDataTest
passwordUTF8Test(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
}
+ public void testPasswordAES256WithPRF()
+ throws Exception
+ {
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC, PasswordRecipient.PRF.HMacSHA1);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC, PasswordRecipient.PRF.HMacSHA224);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC, PasswordRecipient.PRF.HMacSHA256);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC, PasswordRecipient.PRF.HMacSHA384);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC, PasswordRecipient.PRF.HMacSHA512);
+ }
+
+ public void testNoSaltOrIterationCount()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(CMSAlgorithm.AES256_CBC, "abc\u5639\u563b".toCharArray()).setProvider(BC).setPRF(PasswordRecipient.PRF.HMacSHA1));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ assertEquals(AlgorithmIdentifier.getInstance(recipient.getKeyEncryptionAlgorithm().getParameters()).getAlgorithm(), CMSAlgorithm.AES256_CBC);
+ assertEquals(PBKDF2Params.getInstance(recipient.getKeyDerivationAlgorithm().getParameters()).getPrf(), PasswordRecipient.PRF.HMacSHA1.getAlgorithmID());
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+
+ // try lightweight recipient
+ recData = recipient.getContent(new BcPasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
public void testRFC4134ex5_1()
throws Exception
{
@@ -1597,16 +1711,16 @@ public class NewEnvelopedDataTest
CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_1);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals("1.2.840.113549.3.7", ed.getEncryptionAlgOID());
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient((PrivateKey)key).setProvider(BC));
@@ -1628,18 +1742,18 @@ public class NewEnvelopedDataTest
CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_2);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals("1.2.840.113549.3.2", ed.getEncryptionAlgOID());
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
while (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData;
if (recipient instanceof KeyTransRecipientInformation)
@@ -1661,7 +1775,7 @@ public class NewEnvelopedDataTest
{
CMSEnvelopedData env = new CMSEnvelopedData(CMSSampleMessages.originatorMessage);
- RecipientInformationStore recipients = env.getRecipientInfos();
+ RecipientInformationStore recipients = env.getRecipientInfos();
OriginatorInformation origInfo = env.getOriginatorInfo();
@@ -1734,16 +1848,16 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "password".toCharArray()).setProvider(BC).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setSaltAndIterationCount(new byte[20], 5));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(),
- CMSEnvelopedDataGenerator.AES128_CBC);
+ CMSEnvelopedDataGenerator.AES128_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
@@ -1763,7 +1877,7 @@ public class NewEnvelopedDataTest
//
it = c.iterator();
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setProvider(BC));
assertEquals(true, Arrays.equals(data, recData));
@@ -1779,23 +1893,74 @@ public class NewEnvelopedDataTest
edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "abc\u5639\u563b".toCharArray()).setProvider(BC).setSaltAndIterationCount(new byte[20], 5));
CMSEnvelopedData ed = edGen.generate(
- new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void passwordUTF8Test(String algorithm, PasswordRecipient.PRF prf)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "abc\u5639\u563b".toCharArray()).setProvider(BC).setPRF(prf).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
assertEquals(ed.getEncryptionAlgOID(),
- CMSEnvelopedDataGenerator.AES128_CBC);
+ CMSEnvelopedDataGenerator.AES128_CBC);
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ assertEquals(AlgorithmIdentifier.getInstance(recipient.getKeyEncryptionAlgorithm().getParameters()).getAlgorithm().getId(), algorithm);
+ assertEquals(PBKDF2Params.getInstance(recipient.getKeyDerivationAlgorithm().getParameters()).getPrf(), prf.getAlgorithmID());
byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
assertEquals(true, Arrays.equals(data, recData));
+
+ // try lightweight recipient
+ recData = recipient.getContent(new BcPasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()));
+ assertEquals(true, Arrays.equals(data, recData));
}
else
{
@@ -1807,10 +1972,46 @@ public class NewEnvelopedDataTest
//
it = c.iterator();
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
assertEquals(true, Arrays.equals(data, recData));
+
+ // try lightweight generator.
+ edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcPasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "abc\u5639\u563b".toCharArray()).setPRF(prf).setSaltAndIterationCount(new byte[20], 5));
+
+ ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ c = recipients.getRecipients();
+ it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient1 = (PasswordRecipientInformation)it.next();
+
+ assertEquals(AlgorithmIdentifier.getInstance(recipient1.getKeyEncryptionAlgorithm().getParameters()).getAlgorithm().getId(), algorithm);
+ assertEquals(PBKDF2Params.getInstance(recipient1.getKeyDerivationAlgorithm().getParameters()).getPrf(), prf.getAlgorithmID());
+
+ recData = recipient1.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+
+ // try lightweight recipient
+ recData = recipient1.getContent(new BcPasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
}
private void verifyECKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
@@ -1820,16 +2021,16 @@ public class NewEnvelopedDataTest
CMSEnvelopedData ed = new CMSEnvelopedData(message);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
assertEquals(wrapAlg, ed.getEncryptionAlgOID());
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals("1.3.133.16.840.63.0.2", recipient.getKeyEncryptionAlgOID());
@@ -1850,16 +2051,16 @@ public class NewEnvelopedDataTest
CMSEnvelopedData ed = new CMSEnvelopedData(message);
- RecipientInformationStore recipients = ed.getRecipientInfos();
+ RecipientInformationStore recipients = ed.getRecipientInfos();
- Collection c = recipients.getRecipients();
- Iterator it = c.iterator();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
assertEquals(wrapAlg, ed.getEncryptionAlgOID());
if (it.hasNext())
{
- RecipientInformation recipient = (RecipientInformation)it.next();
+ RecipientInformation recipient = (RecipientInformation)it.next();
assertEquals("1.3.133.16.840.63.0.16", recipient.getKeyEncryptionAlgOID());
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewSignedDataTest.java b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewSignedDataTest.java
index 9d6e0186..8b7b54e1 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/test/NewSignedDataTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/test/NewSignedDataTest.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
@@ -54,6 +55,8 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cms.CMSAbsentContent;
import org.bouncycastle.cms.CMSAlgorithm;
+import org.bouncycastle.cms.CMSAttributeTableGenerationException;
+import org.bouncycastle.cms.CMSAttributeTableGenerator;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
@@ -1153,6 +1156,56 @@ public class NewSignedDataTest
verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
}
+ public void testRemoveAttribute()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setSignedAttributeGenerator(new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ AttributeTable table = new DefaultSignedAttributeTableGenerator().getAttributes(parameters);
+
+ return table.remove(CMSAttributes.cmsAlgorithmProtect);
+ }
+ });
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+
+ // for JDK1.4 build
+ Assert.assertNull(((SignerInformation)s.getSignerInfos().iterator().next()).getSignedAttributes().get(CMSAttributes.cmsAlgorithmProtect));
+
+ //
+ // compute expected content digest
+ //
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
public void testSignerInformationExtension()
throws Exception
{
@@ -1331,16 +1384,18 @@ public class NewSignedDataTest
rsaPSSTest("SHA384withRSAandMGF1");
}
+ // RFC 5754 update
public void testSHA224WithRSAEncapsulated()
throws Exception
{
- encapsulatedTest(_signKP, _signCert, "SHA224withRSA");
+ encapsulatedTest(_signKP, _signCert, "SHA224withRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
}
-
+
+ // RFC 5754 update
public void testSHA256WithRSAEncapsulated()
throws Exception
{
- encapsulatedTest(_signKP, _signCert, "SHA256withRSA");
+ encapsulatedTest(_signKP, _signCert, "SHA256withRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
}
public void testRIPEMD128WithRSAEncapsulated()
@@ -1729,6 +1784,16 @@ public class NewSignedDataTest
String signatureAlgorithm)
throws Exception
{
+ encapsulatedTest(signaturePair, signatureCert, signatureAlgorithm, null);
+ }
+
+ private void encapsulatedTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String signatureAlgorithm,
+ ASN1ObjectIdentifier sigAlgOid)
+ throws Exception
+ {
List certList = new ArrayList();
List crlList = new ArrayList();
CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
@@ -1775,6 +1840,12 @@ public class NewSignedDataTest
Iterator certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+ if (sigAlgOid != null)
+ {
+ assertEquals(sigAlgOid.getId(), signer.getEncryptionAlgOID());
+ assertEquals(DERNull.INSTANCE, ASN1Primitive.fromByteArray(signer.getEncryptionAlgParams()));
+ }
+
digestAlgorithms.remove(signer.getDigestAlgorithmID());
assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
diff --git a/bcpkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java b/bcpkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java
index ac1a6b7d..82593a86 100644
--- a/bcpkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java
+++ b/bcpkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java
@@ -18,7 +18,7 @@ public class DVCSResponse
private org.bouncycastle.asn1.dvcs.DVCSResponse asn1;
/**
- * Constructs DVCRequest from CMS SignedData object.
+ * Constructs DVCResponse from CMS SignedData object.
*
* @param signedData the CMS SignedData object containing the request
* @throws org.bouncycastle.dvcs.DVCSConstructionException
@@ -30,7 +30,7 @@ public class DVCSResponse
}
/**
- * Construct a DVCS Request from a ContentInfo
+ * Construct a DVCS Response from a ContentInfo
*
* @param contentInfo the contentInfo representing the DVCSRequest
* @throws org.bouncycastle.dvcs.DVCSConstructionException
@@ -42,7 +42,7 @@ public class DVCSResponse
if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType()))
{
- throw new DVCSConstructionException("ContentInfo not a DVCS Request");
+ throw new DVCSConstructionException("ContentInfo not a DVCS Response");
}
try
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java b/bcpkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
index 54988fe0..ed73228c 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
@@ -20,6 +20,7 @@ import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.io.pem.PemGenerationException;
import org.bouncycastle.util.io.pem.PemHeader;
@@ -149,6 +150,11 @@ public class MiscPEMGenerator
type = "CERTIFICATE REQUEST";
encoding = ((PKCS10CertificationRequest)o).getEncoded();
}
+ else if (o instanceof PKCS8EncryptedPrivateKeyInfo)
+ {
+ type = "ENCRYPTED PRIVATE KEY";
+ encoding = ((PKCS8EncryptedPrivateKeyInfo)o).getEncoded();
+ }
else if (o instanceof ContentInfo)
{
type = "PKCS7";
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java b/bcpkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
index fb89cf08..99f9872a 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
@@ -2,6 +2,7 @@ package org.bouncycastle.openssl;
/**
* call back to allow a password to be fetched when one is requested.
+ * @deprecated no longer used.
*/
public interface PasswordFinder
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java b/bcpkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java
index e5829011..57a12287 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/bc/PEMUtilities.java
@@ -12,7 +12,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
@@ -194,7 +194,7 @@ class PEMUtilities
throw new EncryptionException("unknown AES encryption with private key: " + dekAlgName);
}
sKey = getKey(password, keyBits / 8, salt);
- engine = new AESFastEngine();
+ engine = new AESEngine();
}
else
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java b/bcpkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java
index 0107f4a2..38ffe691 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java
@@ -110,6 +110,18 @@ public class JcaPEMKeyConverter
algName = algorithm.getId();
}
- return helper.createKeyFactory(algName);
+ try
+ {
+ return helper.createKeyFactory(algName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (algName.equals("ECDSA"))
+ {
+ return helper.createKeyFactory("EC"); // try a fall back
+ }
+
+ throw e;
+ }
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/test/ParserTest.java b/bcpkix/src/main/java/org/bouncycastle/openssl/test/ParserTest.java
index 054abdef..338fe7d6 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/test/ParserTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/test/ParserTest.java
@@ -37,7 +37,6 @@ import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.openssl.X509TrustedCertificateBlock;
import org.bouncycastle.openssl.bc.BcPEMDecryptorProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
@@ -54,23 +53,6 @@ import org.bouncycastle.util.test.SimpleTest;
public class ParserTest
extends SimpleTest
{
- private static class Password
- implements PasswordFinder
- {
- char[] password;
-
- Password(
- char[] word)
- {
- this.password = word;
- }
-
- public char[] getPassword()
- {
- return password;
- }
- }
-
public String getName()
{
return "PEMParserTest";
diff --git a/bcpkix/src/main/java/org/bouncycastle/openssl/test/WriterTest.java b/bcpkix/src/main/java/org/bouncycastle/openssl/test/WriterTest.java
index 783bce5a..19ba64f5 100644
--- a/bcpkix/src/main/java/org/bouncycastle/openssl/test/WriterTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/openssl/test/WriterTest.java
@@ -21,7 +21,6 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.openssl.bc.BcPEMDecryptorProvider;
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
@@ -76,23 +75,6 @@ public class WriterTest
"RC2-64-CBC",
};
- private class Password
- implements PasswordFinder
- {
- private final char[] password;
-
- public Password(
- char[] word)
- {
- this.password = (char[]) word.clone();
- }
-
- public char[] getPassword()
- {
- return (char[]) password.clone();
- }
- }
-
public String getName()
{
return "PEMWriterTest";
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java
index a0bba2a5..1f48c531 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultAlgorithmNameFinder.java
@@ -38,7 +38,7 @@ public class DefaultAlgorithmNameFinder
algorithms.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410-94");
algorithms.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411");
algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1WITHCVC-ECDSA");
- algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHPCVC-ECDSA");
+ algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHCVC-ECDSA");
algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256WITHCVC-ECDSA");
algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384WITHCVC-ECDSA");
algorithms.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512WITHCVC-ECDSA");
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
index fca5693c..ccf4fc2b 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
@@ -5,6 +5,8 @@ import java.util.Map;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
@@ -45,11 +47,30 @@ public class DefaultDigestAlgorithmIdentifierFinder
digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512);
digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, NISTObjectIdentifiers.id_sha512);
+
digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256);
digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384);
digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224);
+ digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256);
+ digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384);
+ digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512);
+ digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224);
+ digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256);
+ digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384);
+ digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512);
+ digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224);
+ digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256);
+ digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384);
+ digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512);
+
digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);
digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);
digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);
@@ -57,6 +78,9 @@ public class DefaultDigestAlgorithmIdentifierFinder
digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);
digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);
+ digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA3_512, NISTObjectIdentifiers.id_sha3_512);
+ digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA512, NISTObjectIdentifiers.id_sha512);
+
digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
index 3de36a13..c7eef850 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -9,6 +9,7 @@ import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
@@ -92,6 +93,9 @@ public class DefaultSignatureAlgorithmIdentifierFinder
algorithms.put("SHA256WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
algorithms.put("SHA384WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
algorithms.put("SHA512WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+ algorithms.put("SHA3-512WITHSPHINCS256", BCObjectIdentifiers.sphincs256_with_SHA3_512);
+ algorithms.put("SHA512WITHSPHINCS256", BCObjectIdentifiers.sphincs256_with_SHA512);
+
//
// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
// The parameters field SHALL be NULL for RSA based signature algorithms.
@@ -114,6 +118,12 @@ public class DefaultSignatureAlgorithmIdentifierFinder
noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
//
+ // SPHINCS-256
+ //
+ noParams.add(BCObjectIdentifiers.sphincs256_with_SHA512);
+ noParams.add(BCObjectIdentifiers.sphincs256_with_SHA3_512);
+
+ //
// PKCS 1.5 encrypted algorithms
//
pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java b/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
index 655b695b..ea563d5a 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
@@ -22,6 +22,7 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.operator.OperatorCreationException;
@@ -69,6 +70,34 @@ public class BcDefaultDigestProvider
return new SHA512Digest();
}
});
+ table.put(NISTObjectIdentifiers.id_sha3_224, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA3Digest(224);
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha3_256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA3Digest(256);
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha3_384, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA3Digest(384);
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha3_512, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA3Digest(512);
+ }
+ });
table.put(PKCSObjectIdentifiers.md5, new BcDigestProvider()
{
public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java
index 31af916f..55831943 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java
@@ -59,6 +59,7 @@ public class JcaContentSignerBuilder
try
{
final Signature sig = helper.createSignature(sigAlgId);
+ final AlgorithmIdentifier signatureAlgId = sigAlgId;
if (random != null)
{
@@ -75,7 +76,7 @@ public class JcaContentSignerBuilder
public AlgorithmIdentifier getAlgorithmIdentifier()
{
- return sigAlgId;
+ return signatureAlgId;
}
public OutputStream getOutputStream()
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
index 6ae402d7..b8063b4c 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
@@ -8,12 +8,22 @@ import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
@@ -56,6 +66,20 @@ public class JceAsymmetricKeyWrapper
this.publicKey = publicKey;
}
+ /**
+ * Create a wrapper, overriding the algorithm type that is stored in the public key.
+ *
+ * @param algorithmParameterSpec the parameterSpec for encryption algorithm to be used.
+ * @param publicKey the public key to be used.
+ */
+ public JceAsymmetricKeyWrapper(AlgorithmParameterSpec algorithmParameterSpec, PublicKey publicKey)
+ {
+ super(extractFromSpec(algorithmParameterSpec));
+
+ this.publicKey = publicKey;
+ }
+
+
public JceAsymmetricKeyWrapper setProvider(Provider provider)
{
this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
@@ -154,4 +178,67 @@ public class JceAsymmetricKeyWrapper
return encryptedKeyBytes;
}
+
+ private static AlgorithmIdentifier extractFromSpec(AlgorithmParameterSpec algorithmParameterSpec)
+ {
+ if (algorithmParameterSpec instanceof OAEPParameterSpec)
+ {
+ OAEPParameterSpec oaepSpec = (OAEPParameterSpec)algorithmParameterSpec;
+
+ if (oaepSpec.getMGFAlgorithm().equals(OAEPParameterSpec.DEFAULT.getMGFAlgorithm()))
+ {
+ if (oaepSpec.getPSource() instanceof PSource.PSpecified)
+ {
+ return new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP,
+ new RSAESOAEPparams(getDigest(oaepSpec.getDigestAlgorithm()),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, getDigest(((MGF1ParameterSpec)oaepSpec.getMGFParameters()).getDigestAlgorithm())),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(((PSource.PSpecified)oaepSpec.getPSource()).getValue()))));
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown PSource: " + oaepSpec.getPSource().getAlgorithm());
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown MGF: " + oaepSpec.getMGFAlgorithm());
+ }
+ }
+
+ throw new IllegalArgumentException("unknown spec: " + algorithmParameterSpec.getClass().getName());
+ }
+
+ private static final Map digests = new HashMap();
+
+ static
+ {
+ digests.put("SHA-1", new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE));
+ digests.put("SHA-1", new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE));
+ digests.put("SHA224", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE));
+ digests.put("SHA-224", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE));
+ digests.put("SHA256", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE));
+ digests.put("SHA-256", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE));
+ digests.put("SHA384", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE));
+ digests.put("SHA-384", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE));
+ digests.put("SHA512", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE));
+ digests.put("SHA-512", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE));
+ digests.put("SHA512/224", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_224, DERNull.INSTANCE));
+ digests.put("SHA-512/224", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_224, DERNull.INSTANCE));
+ digests.put("SHA-512(224)", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_224, DERNull.INSTANCE));
+ digests.put("SHA512/256", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256, DERNull.INSTANCE));
+ digests.put("SHA-512/256", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256, DERNull.INSTANCE));
+ digests.put("SHA-512(256)", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256, DERNull.INSTANCE));
+ }
+
+ private static AlgorithmIdentifier getDigest(String digest)
+ {
+ AlgorithmIdentifier algId = (AlgorithmIdentifier)digests.get(digest);
+
+ if (algId != null)
+ {
+ return algId;
+ }
+
+ throw new IllegalArgumentException("unknown digest name: " + digest);
+ }
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
index 65a771f4..f4c9c038 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
@@ -377,7 +377,7 @@ class OperatorHelper
String name = MessageDigestUtils.getDigestName(oid);
int dIndex = name.indexOf('-');
- if (dIndex > 0)
+ if (dIndex > 0 && !name.startsWith("SHA3"))
{
return name.substring(0, dIndex) + name.substring(dIndex + 1);
}
@@ -388,7 +388,6 @@ class OperatorHelper
public X509Certificate convertCertificate(X509CertificateHolder certHolder)
throws CertificateException
{
-
try
{
CertificateFactory certFact = helper.createCertificateFactory("X.509");
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/test/AllTests.java b/bcpkix/src/main/java/org/bouncycastle/operator/test/AllTests.java
index 2065ebd5..d3410155 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/test/AllTests.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/test/AllTests.java
@@ -1,16 +1,30 @@
package org.bouncycastle.operator.test;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import junit.framework.Assert;
import junit.framework.TestCase;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.AlgorithmNameFinder;
import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
+import org.bouncycastle.operator.jcajce.JceAsymmetricKeyWrapper;
+import org.bouncycastle.util.encoders.Hex;
public class AllTests
extends TestCase
@@ -19,6 +33,14 @@ public class AllTests
private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
private static final String TEST_DATA_HOME = "bc.test.data.home";
+ public void setUp()
+ {
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
public void testAlgorithmNameFinder()
throws Exception
{
@@ -45,4 +67,38 @@ public class AllTests
assertEquals(nameFinder.getAlgorithmName(Extension.authorityKeyIdentifier), Extension.authorityKeyIdentifier.getId());
}
+ public void testOaepWrap()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(2048);
+
+ KeyPair kp = kGen.generateKeyPair();
+
+ checkAlgorithmId(kp, "SHA-1", OIWObjectIdentifiers.idSHA1);
+ checkAlgorithmId(kp, "SHA-224", NISTObjectIdentifiers.id_sha224);
+ checkAlgorithmId(kp, "SHA-256", NISTObjectIdentifiers.id_sha256);
+ checkAlgorithmId(kp, "SHA-384", NISTObjectIdentifiers.id_sha384);
+ checkAlgorithmId(kp, "SHA-512", NISTObjectIdentifiers.id_sha512);
+ checkAlgorithmId(kp, "SHA-512/224", NISTObjectIdentifiers.id_sha512_224);
+ checkAlgorithmId(kp, "SHA-512/256", NISTObjectIdentifiers.id_sha512_256);
+ checkAlgorithmId(kp, "SHA-512(224)", NISTObjectIdentifiers.id_sha512_224);
+ checkAlgorithmId(kp, "SHA-512(256)", NISTObjectIdentifiers.id_sha512_256);
+ }
+
+ private void checkAlgorithmId(KeyPair kp, String digest, ASN1ObjectIdentifier digestOid)
+ {
+ JceAsymmetricKeyWrapper wrapper = new JceAsymmetricKeyWrapper(
+ new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(digest), new PSource.PSpecified(Hex.decode("beef"))),
+ kp.getPublic()).setProvider(BC);
+
+ Assert.assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, wrapper.getAlgorithmIdentifier().getAlgorithm());
+ RSAESOAEPparams oaepParams = RSAESOAEPparams.getInstance(wrapper.getAlgorithmIdentifier().getParameters());
+ Assert.assertEquals(digestOid, oaepParams.getHashAlgorithm().getAlgorithm());
+ Assert.assertEquals(PKCSObjectIdentifiers.id_mgf1, oaepParams.getMaskGenAlgorithm().getAlgorithm());
+ Assert.assertEquals(new AlgorithmIdentifier(digestOid, DERNull.INSTANCE), oaepParams.getMaskGenAlgorithm().getParameters());
+ Assert.assertEquals(PKCSObjectIdentifiers.id_pSpecified, oaepParams.getPSourceAlgorithm().getAlgorithm());
+ Assert.assertEquals(new DEROctetString(Hex.decode("beef")), oaepParams.getPSourceAlgorithm().getParameters());
+ }
} \ No newline at end of file
diff --git a/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java b/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java
index e39025be..1e709631 100644
--- a/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java
+++ b/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java
@@ -10,7 +10,6 @@ import org.bouncycastle.asn1.pkcs.MacData;
import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
import org.bouncycastle.asn1.pkcs.Pfx;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.util.Arrays;
/**
@@ -29,11 +28,11 @@ public class PKCS12PfxPdu
}
catch (ClassCastException e)
{
- throw new CertIOException("malformed data: " + e.getMessage(), e);
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
}
catch (IllegalArgumentException e)
{
- throw new CertIOException("malformed data: " + e.getMessage(), e);
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java b/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java
index 37f1ed84..a1c9164c 100644
--- a/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java
+++ b/bcpkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java
@@ -6,7 +6,6 @@ import java.io.IOException;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.operator.InputDecryptor;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.util.io.Streams;
@@ -27,11 +26,11 @@ public class PKCS8EncryptedPrivateKeyInfo
}
catch (ClassCastException e)
{
- throw new CertIOException("malformed data: " + e.getMessage(), e);
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
}
catch (IllegalArgumentException e)
{
- throw new CertIOException("malformed data: " + e.getMessage(), e);
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java b/bcpkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java
index 361be0ce..06d60d21 100644
--- a/bcpkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java
@@ -9,7 +9,6 @@ import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.PBEParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
@@ -115,7 +114,7 @@ public class JcePKCSPBEOutputEncryptorBuilder
try
{
- if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ if (isPKCS12(algorithm))
{
cipher = helper.createCipher(algorithm.getId());
@@ -160,11 +159,11 @@ public class JcePKCSPBEOutputEncryptorBuilder
{
if (isPKCS12(encryptionAlg.getAlgorithm()))
{
- return new GenericKey(encryptionAlg, PKCS5PasswordToBytes(password));
+ return new GenericKey(encryptionAlg, PKCS12PasswordToBytes(password));
}
else
{
- return new GenericKey(encryptionAlg, PKCS12PasswordToBytes(password));
+ return new GenericKey(encryptionAlg, PKCS5PasswordToBytes(password));
}
}
};
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java
index fa7c9f78..0572fd5e 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java
@@ -148,12 +148,12 @@ public class TimeStampRequest
if (!algorithms.contains(this.getMessageImprintAlgOID()))
{
- throw new TSPValidationException("request contains unknown algorithm.", PKIFailureInfo.badAlg);
+ throw new TSPValidationException("request contains unknown algorithm", PKIFailureInfo.badAlg);
}
if (policies != null && this.getReqPolicy() != null && !policies.contains(this.getReqPolicy()))
{
- throw new TSPValidationException("request contains unknown policy.", PKIFailureInfo.unacceptedPolicy);
+ throw new TSPValidationException("request contains unknown policy", PKIFailureInfo.unacceptedPolicy);
}
if (this.getExtensions() != null && extensions != null)
@@ -161,10 +161,10 @@ public class TimeStampRequest
Enumeration en = this.getExtensions().oids();
while(en.hasMoreElements())
{
- String oid = ((ASN1ObjectIdentifier)en.nextElement()).getId();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)en.nextElement();
if (!extensions.contains(oid))
{
- throw new TSPValidationException("request contains unknown extension.", PKIFailureInfo.unacceptedExtension);
+ throw new TSPValidationException("request contains unknown extension", PKIFailureInfo.unacceptedExtension);
}
}
}
@@ -173,7 +173,7 @@ public class TimeStampRequest
if (digestLength != this.getMessageImprintDigest().length)
{
- throw new TSPValidationException("imprint digest the wrong length.", PKIFailureInfo.badDataFormat);
+ throw new TSPValidationException("imprint digest the wrong length", PKIFailureInfo.badDataFormat);
}
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java
index 8ab68aa4..f6b0ffb4 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java
@@ -19,6 +19,7 @@ import org.bouncycastle.asn1.cmp.PKIStatus;
import org.bouncycastle.asn1.cmp.PKIStatusInfo;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.tsp.TimeStampResp;
+import org.bouncycastle.asn1.x509.Extensions;
/**
* Generator for RFC 3161 Time Stamp Responses.
@@ -214,6 +215,30 @@ public class TimeStampResponseGenerator
String statusString)
throws TSPException
{
+ return generateGrantedResponse(request, serialNumber, genTime, statusString, null);
+ }
+
+ /**
+ * Return a granted response, if the passed in request passes validation with the passed in status string and extra extensions.
+ * <p>
+ * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
+ * be thrown. The parent TSPException will only occur on some sort of system failure.
+ * </p>
+ * @param request the request this response is for.
+ * @param serialNumber serial number for the response token.
+ * @param genTime generation time for the response token.
+ * @param additionalExtensions extra extensions to be added to the response token.
+ * @return the TimeStampResponse with a status of PKIStatus.GRANTED
+ * @throws TSPException on validation exception or internal error.
+ */
+ public TimeStampResponse generateGrantedResponse(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime,
+ String statusString,
+ Extensions additionalExtensions)
+ throws TSPException
+ {
if (genTime == null)
{
throw new TSPValidationException("The time source is not available.", PKIFailureInfo.timeNotAvailable);
@@ -234,7 +259,7 @@ public class TimeStampResponseGenerator
ContentInfo tstTokenContentInfo;
try
{
- tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime).toCMSSignedData().toASN1Structure();
+ tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime, additionalExtensions).toCMSSignedData().toASN1Structure();
}
catch (TSPException e)
{
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java
index 40c1f7f2..6577d190 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java
@@ -3,13 +3,17 @@ package org.bouncycastle.tsp;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.SimpleTimeZone;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encoding;
@@ -28,6 +32,8 @@ import org.bouncycastle.asn1.tsp.Accuracy;
import org.bouncycastle.asn1.tsp.MessageImprint;
import org.bouncycastle.asn1.tsp.TSTInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.IssuerSerial;
@@ -71,11 +77,34 @@ import org.bouncycastle.util.Store;
*/
public class TimeStampTokenGenerator
{
- int accuracySeconds = -1;
+ /**
+ * Create time-stamps with a resolution of 1 second (the default).
+ */
+ public static final int R_SECONDS = 0;
+
+ /**
+ * Create time-stamps with a resolution of 1 tenth of a second.
+ */
+ public static final int R_TENTHS_OF_SECONDS = 1;
+
+ /**
+ * Create time-stamps with a resolution of 1 microsecond.
+ */
+ public static final int R_MICROSECONDS = 2;
+
+ /**
+ * Create time-stamps with a resolution of 1 millisecond.
+ */
+ public static final int R_MILLISECONDS = 3;
+
+ private int resolution = R_SECONDS;
+ private Locale locale = null; // default locale
+
+ private int accuracySeconds = -1;
- int accuracyMillis = -1;
+ private int accuracyMillis = -1;
- int accuracyMicros = -1;
+ private int accuracyMicros = -1;
boolean ordering = false;
@@ -245,6 +274,27 @@ public class TimeStampTokenGenerator
otherRevoc.put(otherRevocationInfoFormat, otherRevocationInfos.getMatches(null));
}
+ /**
+ * Set the resolution of the time stamp - R_SECONDS (the default), R_TENTH_OF_SECONDS, R_MICROSECONDS, R_MILLISECONDS
+ *
+ * @param resolution resolution of timestamps to be produced.
+ */
+ public void setResolution(int resolution)
+ {
+ this.resolution = resolution;
+ }
+
+ /**
+ * Set a Locale for time creation - you may need to use this if the default locale
+ * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+ *
+ * @param locale a locale to use for converting system time into a GeneralizedTime.
+ */
+ public void setLocale(Locale locale)
+ {
+ this.locale = locale;
+ }
+
public void setAccuracySeconds(int accuracySeconds)
{
this.accuracySeconds = accuracySeconds;
@@ -285,10 +335,30 @@ public class TimeStampTokenGenerator
Date genTime)
throws TSPException
{
+ return generate(request, serialNumber, genTime, null);
+ }
+
+ /**
+ * Generate a TimeStampToken for the passed in request and serialNumber marking it with the passed in genTime.
+ *
+ * @param request the originating request.
+ * @param serialNumber serial number for the TimeStampToken
+ * @param genTime token generation time.
+ * @param additionalExtensions extra extensions to be added to the response token.
+ * @return a TimeStampToken
+ * @throws TSPException
+ */
+ public TimeStampToken generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime,
+ Extensions additionalExtensions)
+ throws TSPException
+ {
ASN1ObjectIdentifier digestAlgOID = request.getMessageImprintAlgOID();
AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE);
- MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest());
+ MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest());
Accuracy accuracy = null;
if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
@@ -320,7 +390,7 @@ public class TimeStampTokenGenerator
derOrdering = ASN1Boolean.getInstance(ordering);
}
- ASN1Integer nonce = null;
+ ASN1Integer nonce = null;
if (request.getNonce() != null)
{
nonce = new ASN1Integer(request.getNonce());
@@ -332,10 +402,40 @@ public class TimeStampTokenGenerator
tsaPolicy = request.getReqPolicy();
}
+ Extensions respExtensions = request.getExtensions();
+ if (additionalExtensions != null)
+ {
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ if (respExtensions != null)
+ {
+ for (Enumeration en = respExtensions.oids(); en.hasMoreElements(); )
+ {
+ extGen.addExtension(respExtensions.getExtension(ASN1ObjectIdentifier.getInstance(en.nextElement())));
+ }
+ }
+ for (Enumeration en = additionalExtensions.oids(); en.hasMoreElements(); )
+ {
+ extGen.addExtension(additionalExtensions.getExtension(ASN1ObjectIdentifier.getInstance(en.nextElement())));
+ }
+
+ respExtensions = extGen.generate();
+ }
+
+ ASN1GeneralizedTime timeStampTime;
+ if (resolution == R_SECONDS)
+ {
+ timeStampTime = (locale == null) ? new ASN1GeneralizedTime(genTime) : new ASN1GeneralizedTime(genTime, locale);
+ }
+ else
+ {
+ timeStampTime = createGeneralizedTime(genTime);
+ }
+
TSTInfo tstInfo = new TSTInfo(tsaPolicy,
messageImprint, new ASN1Integer(serialNumber),
- new ASN1GeneralizedTime(genTime), accuracy, derOrdering,
- nonce, tsa, request.getExtensions());
+ timeStampTime, accuracy, derOrdering,
+ nonce, tsa, respExtensions);
try
{
@@ -377,4 +477,59 @@ public class TimeStampTokenGenerator
throw new TSPException("Exception encoding info", e);
}
}
+
+ // we need to produce a correct DER encoding GeneralizedTime here as the BC ASN.1 library doesn't handle this properly yet.
+ private ASN1GeneralizedTime createGeneralizedTime(Date time)
+ throws TSPException
+ {
+ String format = "yyyyMMddHHmmss.SSS";
+ SimpleDateFormat dateF = (locale == null) ? new SimpleDateFormat(format) : new SimpleDateFormat(format, locale);
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+ StringBuilder sBuild = new StringBuilder(dateF.format(time));
+ int dotIndex = sBuild.indexOf(".");
+
+ if (dotIndex < 0)
+ {
+ // came back in seconds only, just return
+ sBuild.append("Z");
+ return new ASN1GeneralizedTime(sBuild.toString());
+ }
+
+ // trim to resolution
+ switch (resolution)
+ {
+ case R_TENTHS_OF_SECONDS:
+ if (sBuild.length() > dotIndex + 2)
+ {
+ sBuild.delete(dotIndex + 2, sBuild.length());
+ }
+ break;
+ case R_MICROSECONDS:
+ if (sBuild.length() > dotIndex + 3)
+ {
+ sBuild.delete(dotIndex + 3, sBuild.length());
+ }
+ break;
+ case R_MILLISECONDS:
+ // do nothing
+ break;
+ default:
+ throw new TSPException("unknown time-stamp resolution: " + resolution);
+ }
+
+ // remove trailing zeros
+ while (sBuild.charAt(sBuild.length() - 1) == '0')
+ {
+ sBuild.deleteCharAt(sBuild.length() - 1);
+ }
+
+ if (sBuild.length() - 1 == dotIndex)
+ {
+ sBuild.deleteCharAt(sBuild.length() - 1);
+ }
+
+ sBuild.append("Z");
+
+ return new ASN1GeneralizedTime(sBuild.toString());
+ }
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java
index 196088b2..cb39c7a1 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java
@@ -9,6 +9,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.tsp.Accuracy;
import org.bouncycastle.asn1.tsp.TSTInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
public class TimeStampTokenInfo
@@ -71,6 +72,11 @@ public class TimeStampTokenInfo
return tstInfo.getTsa();
}
+ public Extensions getExtensions()
+ {
+ return tstInfo.getExtensions();
+ }
+
/**
* @return the nonce value, null if there isn't one.
*/
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/test/NewTSPTest.java b/bcpkix/src/main/java/org/bouncycastle/tsp/test/NewTSPTest.java
index 3aa3e97e..8c7c4a8e 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/test/NewTSPTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/test/NewTSPTest.java
@@ -6,15 +6,21 @@ import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.SimpleTimeZone;
import junit.framework.TestCase;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.cmp.PKIFailureInfo;
import org.bouncycastle.asn1.cmp.PKIStatus;
import org.bouncycastle.asn1.cms.AttributeTable;
@@ -24,6 +30,9 @@ import org.bouncycastle.asn1.ess.SigningCertificate;
import org.bouncycastle.asn1.ess.SigningCertificateV2;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.IssuerSerial;
@@ -66,53 +75,58 @@ public class NewTSPTest
public void testGeneral()
throws Exception
{
- String signDN = "O=Bouncy Castle, C=AU";
- KeyPair signKP = TSPTestUtil.makeKeyPair();
- X509Certificate signCert = TSPTestUtil.makeCACertificate(signKP,
- signDN, signKP, signDN);
-
- String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
- KeyPair origKP = TSPTestUtil.makeKeyPair();
- X509Certificate origCert = TSPTestUtil.makeCertificate(origKP,
- origDN, signKP, signDN);
-
-
-
- List certList = new ArrayList();
- certList.add(origCert);
- certList.add(signCert);
-
- Store certs = new JcaCertStore(certList);
-
- basicTest(origKP.getPrivate(), origCert, certs);
- basicSha256Test(origKP.getPrivate(), origCert, certs);
- basicTestWithTSA(origKP.getPrivate(), origCert, certs);
- overrideAttrsTest(origKP.getPrivate(), origCert, certs);
- responseValidationTest(origKP.getPrivate(), origCert, certs);
- incorrectHashTest(origKP.getPrivate(), origCert, certs);
- badAlgorithmTest(origKP.getPrivate(), origCert, certs);
- timeNotAvailableTest(origKP.getPrivate(), origCert, certs);
- badPolicyTest(origKP.getPrivate(), origCert, certs);
- tokenEncodingTest(origKP.getPrivate(), origCert, certs);
- certReqTest(origKP.getPrivate(), origCert, certs);
- testAccuracyZeroCerts(origKP.getPrivate(), origCert, certs);
- testAccuracyWithCertsAndOrdering(origKP.getPrivate(), origCert, certs);
- testNoNonse(origKP.getPrivate(), origCert, certs);
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = TSPTestUtil.makeKeyPair();
+ X509Certificate signCert = TSPTestUtil.makeCACertificate(signKP,
+ signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ KeyPair origKP = TSPTestUtil.makeKeyPair();
+ X509Certificate origCert = TSPTestUtil.makeCertificate(origKP,
+ origDN, signKP, signDN);
+
+
+ List certList = new ArrayList();
+ certList.add(origCert);
+ certList.add(signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ basicTest(origKP.getPrivate(), origCert, certs);
+ resolutionTest(origKP.getPrivate(), origCert, certs, TimeStampTokenGenerator.R_SECONDS, "19700101000009Z");
+ resolutionTest(origKP.getPrivate(), origCert, certs, TimeStampTokenGenerator.R_TENTHS_OF_SECONDS, "19700101000009.9Z");
+ resolutionTest(origKP.getPrivate(), origCert, certs, TimeStampTokenGenerator.R_MICROSECONDS, "19700101000009.99Z");
+ resolutionTest(origKP.getPrivate(), origCert, certs, TimeStampTokenGenerator.R_MILLISECONDS, "19700101000009.999Z");
+ basicSha256Test(origKP.getPrivate(), origCert, certs);
+ basicTestWithTSA(origKP.getPrivate(), origCert, certs);
+ overrideAttrsTest(origKP.getPrivate(), origCert, certs);
+ responseValidationTest(origKP.getPrivate(), origCert, certs);
+ incorrectHashTest(origKP.getPrivate(), origCert, certs);
+ badAlgorithmTest(origKP.getPrivate(), origCert, certs);
+ timeNotAvailableTest(origKP.getPrivate(), origCert, certs);
+ badPolicyTest(origKP.getPrivate(), origCert, certs);
+ tokenEncodingTest(origKP.getPrivate(), origCert, certs);
+ certReqTest(origKP.getPrivate(), origCert, certs);
+ testAccuracyZeroCerts(origKP.getPrivate(), origCert, certs);
+ testAccuracyWithCertsAndOrdering(origKP.getPrivate(), origCert, certs);
+ testNoNonse(origKP.getPrivate(), origCert, certs);
+ extensionTest(origKP.getPrivate(), origCert, certs);
+ additionalExtensionTest(origKP.getPrivate(), origCert, certs);
}
-
+
private void basicTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
Store certs)
throws Exception
{
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
- new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
-
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -120,28 +134,82 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
- AttributeTable table = tsToken.getSignedAttributes();
+ AttributeTable table = tsToken.getSignedAttributes();
assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
}
+ private void resolutionTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs,
+ int resolution,
+ String timeString)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ tsTokenGen.setResolution(resolution);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(9999L));
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+ assertEquals(timeString, tsToken.getTimeStampInfo().toASN1Structure().getGenTime().getTimeString());
+
+ // test zero truncation
+ tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(9000L));
+ tsToken = tsResp.getTimeStampToken();
+
+ assertEquals("19700101000009Z", tsToken.getTimeStampInfo().toASN1Structure().getGenTime().getTimeString());
+
+ if (resolution > TimeStampTokenGenerator.R_MICROSECONDS)
+ {
+ tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(9990L));
+ tsToken = tsResp.getTimeStampToken();
+
+ assertEquals("19700101000009.99Z", tsToken.getTimeStampInfo().toASN1Structure().getGenTime().getTimeString());
+ }
+ if (resolution > TimeStampTokenGenerator.R_TENTHS_OF_SECONDS)
+ {
+ tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(9900L));
+ tsToken = tsResp.getTimeStampToken();
+
+ assertEquals("19700101000009.9Z", tsToken.getTimeStampInfo().toASN1Structure().getGenTime().getTimeString());
+ }
+ }
+
private void basicSha256Test(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
Store certs)
throws Exception
{
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
- new JcaSimpleSignerInfoGeneratorBuilder().build("SHA256withRSA", privateKey, cert), new SHA256DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA256withRSA", privateKey, cert), new SHA256DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA256, new byte[32], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA256, new byte[32], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -151,11 +219,11 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
- AttributeTable table = tsToken.getSignedAttributes();
+ AttributeTable table = tsToken.getSignedAttributes();
assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2));
@@ -175,7 +243,7 @@ public class NewTSPTest
}
private void overrideAttrsTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
Store certs)
throws Exception
@@ -227,7 +295,7 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -235,11 +303,11 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
- AttributeTable table = tsToken.getSignedAttributes();
+ AttributeTable table = tsToken.getSignedAttributes();
assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
assertNotNull("no signingCertificateV2 attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2));
@@ -258,19 +326,19 @@ public class NewTSPTest
}
private void basicTestWithTSA(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
Store certs)
throws Exception
{
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
- new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
tsTokenGen.addCertificates(certs);
tsTokenGen.setTSA(new GeneralName(new X500Name("CN=Test")));
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -278,19 +346,58 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
- AttributeTable table = tsToken.getSignedAttributes();
+ AttributeTable table = tsToken.getSignedAttributes();
assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
}
+ private void additionalExtensionTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+ tsTokenGen.setTSA(new GeneralName(new X500Name("CN=Test")));
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.auditIdentity, false, new DERUTF8String("Test"));
+
+ TimeStampResponse tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date(), "Okay", extGen.generate());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+
+ Extensions ext = tsToken.getTimeStampInfo().getExtensions();
+
+ assertEquals(1, ext.getExtensionOIDs().length);
+ assertEquals(new Extension(Extension.auditIdentity, false, new DERUTF8String("Test").getEncoded()), ext.getExtension(Extension.auditIdentity));
+ }
+
private void responseValidationTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -301,7 +408,7 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -309,21 +416,21 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
-
+
//
// check validation
//
tsResp.validate(request);
-
+
try
{
request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(101));
-
+
tsResp.validate(request);
-
+
fail("response validation failed on invalid nonce.");
}
catch (TSPValidationException e)
@@ -334,22 +441,22 @@ public class NewTSPTest
try
{
request = reqGen.generate(TSPAlgorithms.SHA1, new byte[22], BigInteger.valueOf(100));
-
+
tsResp.validate(request);
-
+
fail("response validation failed on wrong digest.");
}
catch (TSPValidationException e)
{
// ignore
}
-
+
try
{
request = reqGen.generate(TSPAlgorithms.MD5, new byte[20], BigInteger.valueOf(100));
-
+
tsResp.validate(request);
-
+
fail("response validation failed on wrong digest.");
}
catch (TSPValidationException e)
@@ -357,21 +464,21 @@ public class NewTSPTest
// ignore
}
}
-
+
private void incorrectHashTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
-
+
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[16]);
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[16]);
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -379,30 +486,30 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
if (tsToken != null)
{
fail("incorrectHash - token not null.");
}
-
- PKIFailureInfo failInfo = tsResp.getFailInfo();
-
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
if (failInfo == null)
{
fail("incorrectHash - failInfo set to null.");
}
-
+
if (failInfo.intValue() != PKIFailureInfo.badDataFormat)
{
fail("incorrectHash - wrong failure info returned.");
}
}
-
+
private void badAlgorithmTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSimpleSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC);
@@ -412,7 +519,7 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
+ TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -420,20 +527,20 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
if (tsToken != null)
{
fail("badAlgorithm - token not null.");
}
- PKIFailureInfo failInfo = tsResp.getFailInfo();
-
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
if (failInfo == null)
{
fail("badAlgorithm - failInfo set to null.");
}
-
+
if (failInfo.intValue() != PKIFailureInfo.badAlg)
{
fail("badAlgorithm - wrong failure info returned.");
@@ -441,9 +548,9 @@ public class NewTSPTest
}
private void timeNotAvailableTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -453,7 +560,7 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
+ TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -470,14 +577,14 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
if (tsToken != null)
{
fail("timeNotAvailable - token not null.");
}
- PKIFailureInfo failInfo = tsResp.getFailInfo();
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
if (failInfo == null)
{
@@ -491,9 +598,9 @@ public class NewTSPTest
}
private void badPolicyTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -503,10 +610,10 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
-
+
reqGen.setReqPolicy(new ASN1ObjectIdentifier("1.1"));
-
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED, new HashSet());
@@ -523,30 +630,30 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
if (tsToken != null)
{
fail("badPolicy - token not null.");
}
- PKIFailureInfo failInfo = tsResp.getFailInfo();
-
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
if (failInfo == null)
{
fail("badPolicy - failInfo set to null.");
}
-
+
if (failInfo.intValue() != PKIFailureInfo.unacceptedPolicy)
{
fail("badPolicy - wrong failure info returned.");
}
}
-
+
private void certReqTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -554,28 +661,28 @@ public class NewTSPTest
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
tsTokenGen.addCertificates(certs);
-
+
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
-
+
//
// request with certReq false
//
reqGen.setCertReq(false);
-
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
TimeStampResponse tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
-
+
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
-
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
assertNull(tsToken.getTimeStampInfo().getGenTimeAccuracy()); // check for abscence of accuracy
-
+
assertEquals("1.2", tsToken.getTimeStampInfo().getPolicy().getId());
-
+
try
{
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
@@ -585,21 +692,21 @@ public class NewTSPTest
fail("certReq(false) verification of token failed.");
}
- Store respCerts = tsToken.getCertificates();
-
- Collection certsColl = respCerts.getMatches(null);
-
+ Store respCerts = tsToken.getCertificates();
+
+ Collection certsColl = respCerts.getMatches(null);
+
if (!certsColl.isEmpty())
{
fail("certReq(false) found certificates in response.");
}
}
-
-
+
+
private void tokenEncodingTest(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -608,10 +715,10 @@ public class NewTSPTest
tsTokenGen.addCertificates(certs);
- TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
- TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
tsResp = new TimeStampResponse(tsResp.getEncoded());
@@ -619,16 +726,16 @@ public class NewTSPTest
if (!Arrays.areEqual(tsResponse.getEncoded(), tsResp.getEncoded())
|| !Arrays.areEqual(tsResponse.getTimeStampToken().getEncoded(),
- tsResp.getTimeStampToken().getEncoded()))
+ tsResp.getTimeStampToken().getEncoded()))
{
fail();
}
}
-
+
private void testAccuracyZeroCerts(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -640,9 +747,9 @@ public class NewTSPTest
tsTokenGen.setAccuracySeconds(1);
tsTokenGen.setAccuracyMillis(2);
tsTokenGen.setAccuracyMicros(3);
-
+
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
@@ -650,10 +757,10 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
-
+
//
// check validation
//
@@ -663,34 +770,34 @@ public class NewTSPTest
// check tstInfo
//
TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
-
+
//
// check accuracy
//
GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
-
+
assertEquals(1, accuracy.getSeconds());
assertEquals(2, accuracy.getMillis());
assertEquals(3, accuracy.getMicros());
-
+
assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
-
+
assertEquals("1.2", tstInfo.getPolicy().getId());
-
+
//
// test certReq
//
Store store = tsToken.getCertificates();
-
+
Collection certificates = store.getMatches(null);
-
+
assertEquals(0, certificates.size());
}
-
+
private void testAccuracyWithCertsAndOrdering(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -702,17 +809,17 @@ public class NewTSPTest
tsTokenGen.setAccuracySeconds(3);
tsTokenGen.setAccuracyMillis(1);
tsTokenGen.setAccuracyMicros(2);
-
+
tsTokenGen.setOrdering(true);
-
+
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
-
+
reqGen.setCertReq(true);
-
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
assertTrue(request.getCertReq());
-
+
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
TimeStampResponse tsResp;
@@ -728,10 +835,10 @@ public class NewTSPTest
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
-
+
//
// check validation
//
@@ -741,38 +848,38 @@ public class NewTSPTest
// check tstInfo
//
TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
-
+
//
// check accuracy
//
GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
-
+
assertEquals(3, accuracy.getSeconds());
assertEquals(1, accuracy.getMillis());
assertEquals(2, accuracy.getMicros());
-
+
assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
-
+
assertEquals("1.2.3", tstInfo.getPolicy().getId());
-
+
assertEquals(true, tstInfo.isOrdered());
-
+
assertEquals(tstInfo.getNonce(), BigInteger.valueOf(100));
-
+
//
// test certReq
//
Store store = tsToken.getCertificates();
-
+
Collection certificates = store.getMatches(null);
-
+
assertEquals(2, certificates.size());
- }
-
+ }
+
private void testNoNonse(
- PrivateKey privateKey,
+ PrivateKey privateKey,
X509Certificate cert,
- Store certs)
+ Store certs)
throws Exception
{
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
@@ -780,22 +887,28 @@ public class NewTSPTest
TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2.3"));
tsTokenGen.addCertificates(certs);
-
+
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
- TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ Set algorithms = new HashSet();
+
+ algorithms.add(TSPAlgorithms.SHA1);
+
+ request.validate(algorithms, new HashSet(), new HashSet());
assertFalse(request.getCertReq());
-
+
TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("24"), new Date());
tsResp = new TimeStampResponse(tsResp.getEncoded());
- TimeStampToken tsToken = tsResp.getTimeStampToken();
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
-
+
//
// check validation
//
@@ -805,29 +918,112 @@ public class NewTSPTest
// check tstInfo
//
TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
-
+
//
// check accuracy
//
GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
-
+
assertNull(accuracy);
-
+
assertEquals(new BigInteger("24"), tstInfo.getSerialNumber());
-
+
assertEquals("1.2.3", tstInfo.getPolicy().getId());
-
+
assertEquals(false, tstInfo.isOrdered());
-
+
assertNull(tstInfo.getNonce());
-
+
//
// test certReq
//
Store store = tsToken.getCertificates();
-
+
Collection certificates = store.getMatches(null);
-
+
assertEquals(0, certificates.size());
- }
+ }
+
+ private void extensionTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ // test case only!!!
+ reqGen.setReqPolicy(Extension.noRevAvail);
+ // test case only!!!
+ reqGen.addExtension(Extension.biometricInfo, true, new DEROctetString(new byte[20]));
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ try
+ {
+ request.validate(new HashSet(), new HashSet(), new HashSet());
+ fail("no exception");
+ }
+ catch (Exception e)
+ {
+ assertEquals(e.getMessage(), "request contains unknown algorithm");
+ }
+
+ Set algorithms = new HashSet();
+
+ algorithms.add(TSPAlgorithms.SHA1);
+
+ try
+ {
+ request.validate(algorithms, new HashSet(), new HashSet());
+ fail("no exception");
+ }
+ catch (Exception e)
+ {
+ assertEquals(e.getMessage(), "request contains unknown policy");
+ }
+
+ Set policies = new HashSet();
+
+ policies.add(Extension.noRevAvail);
+
+ try
+ {
+ request.validate(algorithms, policies, new HashSet());
+ fail("no exception");
+ }
+ catch (Exception e)
+ {
+ assertEquals(e.getMessage(), "request contains unknown extension");
+ }
+
+ Set extensions = new HashSet();
+
+ extensions.add(Extension.biometricInfo);
+
+ // should validate with full set
+ request.validate(algorithms, policies, extensions);
+
+ // should validate with null policy
+ request.validate(algorithms, null, extensions);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+ }
}
diff --git a/bcpkix/src/main/java/org/bouncycastle/tsp/test/ParseTest.java b/bcpkix/src/main/java/org/bouncycastle/tsp/test/ParseTest.java
index 46821d48..7a77a985 100644
--- a/bcpkix/src/main/java/org/bouncycastle/tsp/test/ParseTest.java
+++ b/bcpkix/src/main/java/org/bouncycastle/tsp/test/ParseTest.java
@@ -370,7 +370,7 @@ public class ParseTest
throws Exception
{
requestParse(sha1Request, TSPAlgorithms.SHA1);
-
+
requestParse(sha1noNonse, TSPAlgorithms.SHA1);
requestParse(md5Request, TSPAlgorithms.MD5);
@@ -385,7 +385,8 @@ public class ParseTest
unacceptableResponseParse(unacceptablePolicy);
- generalizedTimeParse(generalizedTime);
+ // TODO: believe it or not but this contains invalid integers
+ //generalizedTimeParse(generalizedTime);
v2SigningResponseParse(v2SigningCertResponse);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/LICENSE.java b/bcprov/src/main/java/org/bouncycastle/LICENSE.java
index 7c0771bb..59730870 100644
--- a/bcprov/src/main/java/org/bouncycastle/LICENSE.java
+++ b/bcprov/src/main/java/org/bouncycastle/LICENSE.java
@@ -5,7 +5,7 @@ import org.bouncycastle.util.Strings;
/**
* The Bouncy Castle License
*
- * Copyright (c) 2000-2015 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org)
+ * Copyright (c) 2000-2016 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org)
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
@@ -26,7 +26,7 @@ import org.bouncycastle.util.Strings;
public class LICENSE
{
public static String licenseText =
- "Copyright (c) 2000-2015 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) "
+ "Copyright (c) 2000-2016 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) "
+ Strings.lineSeparator()
+ Strings.lineSeparator()
+ "Permission is hereby granted, free of charge, to any person obtaining a copy of this software "
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
index fca4e01a..c67e42f3 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
@@ -21,7 +21,7 @@ public abstract class ASN1ApplicationSpecific
{
this.isConstructed = isConstructed;
this.tag = tag;
- this.octets = octets;
+ this.octets = Arrays.clone(octets);
}
/**
@@ -93,7 +93,7 @@ public abstract class ASN1ApplicationSpecific
*/
public byte[] getContents()
{
- return octets;
+ return Arrays.clone(octets);
}
/**
@@ -115,7 +115,7 @@ public abstract class ASN1ApplicationSpecific
public ASN1Primitive getObject()
throws IOException
{
- return new ASN1InputStream(getContents()).readObject();
+ return ASN1Primitive.fromByteArray(getContents());
}
/**
@@ -141,7 +141,7 @@ public abstract class ASN1ApplicationSpecific
tmp[0] |= BERTags.CONSTRUCTED;
}
- return new ASN1InputStream(tmp).readObject();
+ return ASN1Primitive.fromByteArray(tmp);
}
int encodedLength()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
index 195b924f..ca192f31 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
@@ -99,7 +99,18 @@ public class ASN1Enumerated
public ASN1Enumerated(
byte[] bytes)
{
- this.bytes = bytes;
+ if (bytes.length > 1)
+ {
+ if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+ {
+ throw new IllegalArgumentException("malformed enumerated");
+ }
+ if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+ {
+ throw new IllegalArgumentException("malformed enumerated");
+ }
+ }
+ this.bytes = Arrays.clone(bytes);
}
public BigInteger getValue()
@@ -148,7 +159,7 @@ public class ASN1Enumerated
{
if (enc.length > 1)
{
- return new ASN1Enumerated(Arrays.clone(enc));
+ return new ASN1Enumerated(enc);
}
if (enc.length == 0)
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
index dc0ee203..2696add7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
@@ -2,22 +2,41 @@ package org.bouncycastle.asn1;
import java.io.IOException;
+/**
+ * Exception thrown in cases of corrupted or unexpected data in a stream.
+ */
public class ASN1Exception
extends IOException
{
private Throwable cause;
+ /**
+ * Base constructor
+ *
+ * @param message a message concerning the exception.
+ */
ASN1Exception(String message)
{
super(message);
}
+ /**
+ * Constructor when this exception is due to another one.
+ *
+ * @param message a message concerning the exception.
+ * @param cause the exception that caused this exception to be thrown.
+ */
ASN1Exception(String message, Throwable cause)
{
super(message);
this.cause = cause;
}
+ /**
+ * Return the underlying cause of this exception, if any.
+ *
+ * @return the exception causing this one, null if there isn't one.
+ */
public Throwable getCause()
{
return cause;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java
index 50cb7054..3817d82c 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java
@@ -2,14 +2,27 @@ package org.bouncycastle.asn1;
import java.io.OutputStream;
+/**
+ * Basic class for streaming generators.
+ */
public abstract class ASN1Generator
{
protected OutputStream _out;
-
+
+ /**
+ * Base constructor.
+ *
+ * @param out the end output stream that object encodings are written to.
+ */
public ASN1Generator(OutputStream out)
{
_out = out;
}
-
+
+ /**
+ * Return the actual stream object encodings are written to.
+ *
+ * @return the stream that is directly encoded to.
+ */
public abstract OutputStream getRawOutputStream();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
index c3c3f9cf..ab6d2020 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
@@ -89,6 +89,17 @@ public class ASN1Integer
ASN1Integer(byte[] bytes, boolean clone)
{
+ if (bytes.length > 1)
+ {
+ if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+ {
+ throw new IllegalArgumentException("malformed integer");
+ }
+ if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+ {
+ throw new IllegalArgumentException("malformed integer");
+ }
+ }
this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index 46197ce1..73a9d92a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -3,8 +3,8 @@ package org.bouncycastle.asn1;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.bouncycastle.util.Arrays;
@@ -20,9 +20,10 @@ public class ASN1ObjectIdentifier
/**
* return an OID from the passed in object
+ *
* @param obj an ASN1ObjectIdentifier or an object that can be converted into one.
- * @throws IllegalArgumentException if the object cannot be converted.
* @return an ASN1ObjectIdentifier instance, or null.
+ * @throws IllegalArgumentException if the object cannot be converted.
*/
public static ASN1ObjectIdentifier getInstance(
Object obj)
@@ -59,9 +60,9 @@ public class ASN1ObjectIdentifier
* @param obj the tagged object holding the object we want
* @param explicit true if the object is meant to be explicitly
* tagged false otherwise.
+ * @return an ASN1ObjectIdentifier instance, or null.
* @throws IllegalArgumentException if the tagged object cannot
* be converted.
- * @return an ASN1ObjectIdentifier instance, or null.
*/
public static ASN1ObjectIdentifier getInstance(
ASN1TaggedObject obj,
@@ -178,12 +179,12 @@ public class ASN1ObjectIdentifier
this.identifier = identifier;
}
- /**
- * Create 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.
- */
+ /**
+ * Create 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.
+ */
ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID)
{
if (!isValidBranchID(branchID, 0))
@@ -416,32 +417,29 @@ public class ASN1ObjectIdentifier
* The pool is also used by the ASN.1 parsers to limit the number of duplicated OID
* objects in circulation.
* </p>
+ *
* @return a reference to the identifier in the pool.
*/
public ASN1ObjectIdentifier intern()
{
- synchronized (pool)
+ final OidHandle hdl = new OidHandle(getBody());
+ ASN1ObjectIdentifier oid = pool.get(hdl);
+ if (oid == null)
{
- OidHandle hdl = new OidHandle(getBody());
- ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl);
-
- if (oid != null)
- {
- return oid;
- }
- else
+ oid = pool.putIfAbsent(hdl, this);
+ if (oid == null)
{
- pool.put(hdl, this);
- return this;
+ oid = this;
}
}
+ return oid;
}
- private static final Map pool = new HashMap();
+ private static final ConcurrentMap<OidHandle, ASN1ObjectIdentifier> pool = new ConcurrentHashMap<OidHandle, ASN1ObjectIdentifier>();
private static class OidHandle
{
- private int key;
+ private final int key;
private final byte[] enc;
OidHandle(byte[] enc)
@@ -468,17 +466,12 @@ public class ASN1ObjectIdentifier
static ASN1ObjectIdentifier fromOctetString(byte[] enc)
{
- OidHandle hdl = new OidHandle(enc);
-
- synchronized (pool)
+ final OidHandle hdl = new OidHandle(enc);
+ ASN1ObjectIdentifier oid = pool.get(hdl);
+ if (oid == null)
{
- ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl);
- if (oid != null)
- {
- return oid;
- }
+ return new ASN1ObjectIdentifier(enc);
}
-
- return new ASN1ObjectIdentifier(enc);
+ return oid;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
index a3fa4a41..07811d71 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
@@ -5,6 +5,7 @@ import java.io.IOException;
import java.io.InputStream;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
/**
@@ -248,6 +249,6 @@ public abstract class ASN1OctetString
public String toString()
{
- return "#"+new String(Hex.encode(string));
+ return "#"+ Strings.fromByteArray(Hex.encode(string));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
index 995b5e93..509c213c 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
@@ -1,21 +1,40 @@
package org.bouncycastle.asn1;
+/**
+ * Exception thrown when correctly encoded, but unexpected data is found in a stream while building an object.
+ */
public class ASN1ParsingException
extends IllegalStateException
{
private Throwable cause;
+ /**
+ * Base constructor
+ *
+ * @param message a message concerning the exception.
+ */
public ASN1ParsingException(String message)
{
super(message);
}
+ /**
+ * Constructor when this exception is due to another one.
+ *
+ * @param message a message concerning the exception.
+ * @param cause the exception that caused this exception to be thrown.
+ */
public ASN1ParsingException(String message, Throwable cause)
{
super(message);
this.cause = cause;
}
+ /**
+ * Return the underlying cause of this exception, if any.
+ *
+ * @return the exception causing this one, null if there isn't one.
+ */
public Throwable getCause()
{
return cause;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
index 778bea74..808f478e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -143,6 +143,11 @@ public abstract class ASN1TaggedObject
return code;
}
+ /**
+ * Return the tag number associated with this object.
+ *
+ * @return the tag number.
+ */
public int getTagNo()
{
return tagNo;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
index b8df94af..55e695c7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
@@ -3,9 +3,19 @@ package org.bouncycastle.asn1;
import java.io.IOException;
import java.io.OutputStream;
+/**
+ * A generator for indefinite-length OCTET STRINGs
+ */
public class BEROctetStringGenerator
extends BERGenerator
{
+ /**
+ * Use the passed in stream as the target for the generator, writing out the header tag
+ * for a constructed OCTET STRING.
+ *
+ * @param out target stream
+ * @throws IOException if the target stream cannot be written to.
+ */
public BEROctetStringGenerator(OutputStream out)
throws IOException
{
@@ -14,6 +24,15 @@ public class BEROctetStringGenerator
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
}
+ /**
+ * Use the passed in stream as the target for the generator, writing out the header tag
+ * for a tagged constructed OCTET STRING (possibly implicit).
+ *
+ * @param out target stream
+ * @param tagNo the tag number to introduce
+ * @param isExplicit true if this is an explicitly tagged object, false otherwise.
+ * @throws IOException if the target stream cannot be written to.
+ */
public BEROctetStringGenerator(
OutputStream out,
int tagNo,
@@ -24,12 +43,23 @@ public class BEROctetStringGenerator
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
}
-
+
+ /**
+ * Return a stream representing the content target for this OCTET STRING
+ *
+ * @return an OutputStream which chunks data in blocks of 1000 (CER limit).
+ */
public OutputStream getOctetOutputStream()
{
return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
}
+ /**
+ * Return a stream representing the content target for this OCTET STRING
+ *
+ * @param buf the buffer to use for chunking the data.
+ * @return an OutputStream which chunks data in blocks of buf length.
+ */
public OutputStream getOctetOutputStream(
byte[] buf)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
index 1c7132e5..77a3049d 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
@@ -5,6 +5,9 @@ import java.io.InputStream;
import org.bouncycastle.util.io.Streams;
+/**
+ * A parser for indefinite-length OCTET STRINGs.
+ */
public class BEROctetStringParser
implements ASN1OctetStringParser
{
@@ -16,17 +19,33 @@ public class BEROctetStringParser
_parser = parser;
}
+ /**
+ * Return an InputStream representing the contents of the OCTET STRING.
+ *
+ * @return an InputStream with its source as the OCTET STRING content.
+ */
public InputStream getOctetStream()
{
return new ConstructedOctetStream(_parser);
}
+ /**
+ * Return an in-memory, encodable, representation of the OCTET STRING.
+ *
+ * @return a BEROctetString.
+ * @throws IOException if there is an issue loading the data.
+ */
public ASN1Primitive getLoadedObject()
throws IOException
{
return new BEROctetString(Streams.readAll(getOctetStream()));
}
+ /**
+ * Return an BEROctetString representing this parser and its contents.
+ *
+ * @return an BEROctetString
+ */
public ASN1Primitive toASN1Primitive()
{
try
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
index 7117d4fb..f6459b2e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
@@ -3,15 +3,29 @@ package org.bouncycastle.asn1;
import java.io.IOException;
import java.io.OutputStream;
+/**
+ * A class which writes indefinite and definite length objects,
+ */
public class BEROutputStream
extends DEROutputStream
{
+ /**
+ * Base constructor.
+ *
+ * @param os target output stream.
+ */
public BEROutputStream(
OutputStream os)
{
super(os);
}
+ /**
+ * Write out an ASN.1 object.
+ *
+ * @param obj the object to be encoded.
+ * @throws IOException if there is an issue on encoding or output of the object.
+ */
public void writeObject(
Object obj)
throws IOException
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
index 1af0a433..37599fbe 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
@@ -127,7 +127,7 @@ public class BERTaggedObject
}
else
{
- throw new RuntimeException("not implemented: " + obj.getClass().getName());
+ throw new ASN1Exception("not implemented: " + obj.getClass().getName());
}
while (e.hasMoreElements())
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java
index d74bc00e..c789d7cd 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java
@@ -26,6 +26,17 @@ public class DERBitString
{
return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits);
}
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (DERBitString)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
index 376c1fd8..5503feb8 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
@@ -2,6 +2,9 @@ package org.bouncycastle.asn1;
import java.io.IOException;
+/**
+ * Parser class for DER SEQUENCEs.
+ */
public class DERSequenceParser
implements ASN1SequenceParser
{
@@ -12,18 +15,35 @@ public class DERSequenceParser
this._parser = parser;
}
+ /**
+ * Return the next object in the SEQUENCE.
+ *
+ * @return next object in SEQUENCE.
+ * @throws IOException if there is an issue loading the object.
+ */
public ASN1Encodable readObject()
throws IOException
{
return _parser.readObject();
}
+ /**
+ * Return an in memory, encodable, representation of the SEQUENCE.
+ *
+ * @return a DERSequence.
+ * @throws IOException if there is an issue loading the data.
+ */
public ASN1Primitive getLoadedObject()
throws IOException
{
return new DERSequence(_parser.readVector());
}
+ /**
+ * Return a DERSequence representing this parser and its contents.
+ *
+ * @return a DERSequence.
+ */
public ASN1Primitive toASN1Primitive()
{
try
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java
index ac58eacf..1a72a0b1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java
@@ -4,7 +4,7 @@ import java.io.IOException;
import java.util.Enumeration;
/**
- * A DER encoded set object
+ * A DER encoded SET object
*/
public class DERSet
extends ASN1Set
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java
index 17702fa4..d16cb157 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java
@@ -2,6 +2,9 @@ package org.bouncycastle.asn1;
import java.io.IOException;
+/**
+ * Parser class for DER SETs.
+ */
public class DERSetParser
implements ASN1SetParser
{
@@ -12,18 +15,35 @@ public class DERSetParser
this._parser = parser;
}
+ /**
+ * Return the next object in the SET.
+ *
+ * @return next object in SET.
+ * @throws IOException if there is an issue loading the object.
+ */
public ASN1Encodable readObject()
throws IOException
{
return _parser.readObject();
}
+ /**
+ * Return an in memory, encodable, representation of the SET.
+ *
+ * @return a DERSet.
+ * @throws IOException if there is an issue loading the data.
+ */
public ASN1Primitive getLoadedObject()
throws IOException
{
return new DERSet(_parser.readVector(), false);
}
+ /**
+ * Return a DERSet representing this parser and its contents.
+ *
+ * @return a DERSet
+ */
public ASN1Primitive toASN1Primitive()
{
try
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java
index 30744c69..c5c29137 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java
@@ -13,7 +13,7 @@ public class DERT61String
extends ASN1Primitive
implements ASN1String
{
- private final byte[] string;
+ private byte[] string;
/**
* return a T61 string from the passed in object.
@@ -79,7 +79,7 @@ public class DERT61String
public DERT61String(
byte[] string)
{
- this.string = string;
+ this.string = Arrays.clone(string);
}
/**
@@ -90,7 +90,7 @@ public class DERT61String
public DERT61String(
String string)
{
- this(Strings.toByteArray(string));
+ this.string = Strings.toByteArray(string);
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
index 85390990..6b70faab 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
@@ -79,7 +79,7 @@ public class DERUniversalString
public DERUniversalString(
byte[] string)
{
- this.string = string;
+ this.string = Arrays.clone(string);
}
public String getString()
@@ -94,7 +94,7 @@ public class DERUniversalString
}
catch (IOException e)
{
- throw new RuntimeException("internal error encoding BitString");
+ throw new ASN1ParsingException("internal error encoding BitString");
}
byte[] string = bOut.toByteArray();
@@ -115,7 +115,7 @@ public class DERUniversalString
public byte[] getOctets()
{
- return string;
+ return Arrays.clone(string);
}
boolean isConstructed()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java
index c81f0ab9..f6cb49bd 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java
@@ -26,6 +26,17 @@ public class DLBitString
{
return (DERBitString)obj;
}
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (ASN1BitString)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
index 5b95b79e..e34779ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -66,4 +66,27 @@ public interface BCObjectIdentifiers
public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = bc_pbe_sha256_pkcs12.branch("1.22");
/** 1.3.6.1.4.1.22554.1.1.2.2.42 */
public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = bc_pbe_sha256_pkcs12.branch("1.42");
+
+ /**
+ * signature(2) algorithms
+ */
+ public static final ASN1ObjectIdentifier bc_sig = bc.branch("2");
+
+ /**
+ * Sphincs-256
+ */
+ public static final ASN1ObjectIdentifier sphincs256 = bc_sig.branch("1");
+ public static final ASN1ObjectIdentifier sphincs256_with_BLAKE512 = sphincs256.branch("1");
+ public static final ASN1ObjectIdentifier sphincs256_with_SHA512 = sphincs256.branch("2");
+ public static final ASN1ObjectIdentifier sphincs256_with_SHA3_512 = sphincs256.branch("3");
+
+ /**
+ * key_exchange(3) algorithms
+ */
+ public static final ASN1ObjectIdentifier bc_exch = bc.branch("3");
+
+ /**
+ * NewHope
+ */
+ public static final ASN1ObjectIdentifier newHope = bc_exch.branch("1");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java
new file mode 100644
index 00000000..380964b9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java
@@ -0,0 +1,71 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <pre>
+ * EncryptedObjectStoreData ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier
+ * encryptedContent OCTET STRING
+ * }
+ * </pre>
+ */
+public class EncryptedObjectStoreData
+ extends ASN1Object
+{
+ private final AlgorithmIdentifier encryptionAlgorithm;
+ private final ASN1OctetString encryptedContent;
+
+ public EncryptedObjectStoreData(AlgorithmIdentifier encryptionAlgorithm, byte[] encryptedContent)
+ {
+ this.encryptionAlgorithm = encryptionAlgorithm;
+ this.encryptedContent = new DEROctetString(encryptedContent);
+ }
+
+ private EncryptedObjectStoreData(ASN1Sequence seq)
+ {
+ this.encryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+ this.encryptedContent = ASN1OctetString.getInstance(seq.getObjectAt(1));
+ }
+
+ public static EncryptedObjectStoreData getInstance(Object o)
+ {
+ if (o instanceof EncryptedObjectStoreData)
+ {
+ return (EncryptedObjectStoreData)o;
+ }
+ else if (o != null)
+ {
+ return new EncryptedObjectStoreData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public ASN1OctetString getEncryptedContent()
+ {
+ return encryptedContent;
+ }
+
+ public AlgorithmIdentifier getEncryptionAlgorithm()
+ {
+ return encryptionAlgorithm;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(encryptionAlgorithm);
+ v.add(encryptedContent);
+
+ return new DERSequence(v);
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java
new file mode 100644
index 00000000..ec66c08e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.bouncycastle.asn1.x509.Certificate;
+
+/**
+ * <pre>
+ * EncryptedPrivateKeyObjectData ::= SEQUENCE {
+ * encryptedPrivateKeyInfo EncryptedPrivateKeyInfo,
+ * certificates SEQUENCE OF Certificate
+ * }
+ * </pre>
+ */
+public class EncryptedPrivateKeyData
+ extends ASN1Object
+{
+ private final EncryptedPrivateKeyInfo encryptedPrivateKeyInfo;
+ private final Certificate[] certificateChain;
+
+ public EncryptedPrivateKeyData(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo, Certificate[] certificateChain)
+ {
+ this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo;
+ this.certificateChain = new Certificate[certificateChain.length];
+ System.arraycopy(certificateChain, 0, this.certificateChain, 0, certificateChain.length);
+ }
+
+ private EncryptedPrivateKeyData(ASN1Sequence seq)
+ {
+ encryptedPrivateKeyInfo = EncryptedPrivateKeyInfo.getInstance(seq.getObjectAt(0));
+ ASN1Sequence certSeq = ASN1Sequence.getInstance(seq.getObjectAt(1));
+ certificateChain = new Certificate[certSeq.size()];
+ for (int i = 0; i != certificateChain.length; i++)
+ {
+ certificateChain[i] = Certificate.getInstance(certSeq.getObjectAt(i));
+ }
+ }
+
+ public static EncryptedPrivateKeyData getInstance(Object o)
+ {
+ if (o instanceof EncryptedPrivateKeyData)
+ {
+ return (EncryptedPrivateKeyData)o;
+ }
+ else if (o != null)
+ {
+ return new EncryptedPrivateKeyData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public Certificate[] getCertificateChain()
+ {
+ Certificate[] tmp = new Certificate[certificateChain.length];
+
+ System.arraycopy(certificateChain, 0, tmp, 0, certificateChain.length);
+
+ return tmp;
+ }
+
+ public EncryptedPrivateKeyInfo getEncryptedPrivateKeyInfo()
+ {
+ return encryptedPrivateKeyInfo;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(encryptedPrivateKeyInfo);
+ v.add(new DERSequence(certificateChain));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java
new file mode 100644
index 00000000..5b66f68a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ * EncryptedSecretKeyData ::= SEQUENCE {
+ * keyEncryptionAlgorithm AlgorithmIdentifier,
+ * encryptedKeyData OCTET STRING
+ * }
+ * </pre>
+ */
+public class EncryptedSecretKeyData
+ extends ASN1Object
+{
+ private final AlgorithmIdentifier keyEncryptionAlgorithm;
+ private final ASN1OctetString encryptedKeyData;
+
+ public EncryptedSecretKeyData(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] encryptedKeyData)
+ {
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKeyData = new DEROctetString(Arrays.clone(encryptedKeyData));
+ }
+
+ private EncryptedSecretKeyData(ASN1Sequence seq)
+ {
+ this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+ this.encryptedKeyData = ASN1OctetString.getInstance(seq.getObjectAt(1));
+ }
+
+ public static EncryptedSecretKeyData getInstance(Object o)
+ {
+ if (o instanceof EncryptedSecretKeyData)
+ {
+ return (EncryptedSecretKeyData)o;
+ }
+ else if (o != null)
+ {
+ return new EncryptedSecretKeyData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncryptionAlgorithm;
+ }
+
+ public byte[] getEncryptedKeyData()
+ {
+ return Arrays.clone(encryptedKeyData.getOctets());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(keyEncryptionAlgorithm);
+ v.add(encryptedKeyData);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java
new file mode 100644
index 00000000..afe3c92e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectData.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1.bc;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ * ObjectData ::= SEQUENCE {
+ * type INTEGER,
+ * identifier UTF8String,
+ * creationDate GeneralizedTime,
+ * lastModifiedDate GeneralizedTime,
+ * data OCTET STRING,
+ * comment UTF8String OPTIONAL
+ * }
+ * </pre>
+ */
+public class ObjectData
+ extends ASN1Object
+{
+ private final BigInteger type;
+ private final String identifier;
+ private final ASN1GeneralizedTime creationDate;
+ private final ASN1GeneralizedTime lastModifiedDate;
+ private final ASN1OctetString data;
+ private final String comment;
+
+ private ObjectData(ASN1Sequence seq)
+ {
+ this.type = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
+ this.identifier = DERUTF8String.getInstance(seq.getObjectAt(1)).getString();
+ this.creationDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2));
+ this.lastModifiedDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3));
+ this.data = ASN1OctetString.getInstance(seq.getObjectAt(4));
+ this.comment = (seq.size() == 6) ? DERUTF8String.getInstance(seq.getObjectAt(5)).getString() : null;
+ }
+
+ public ObjectData(BigInteger type, String identifier, Date creationDate, Date lastModifiedDate, byte[] data, String comment)
+ {
+ this.type = type;
+ this.identifier = identifier;
+ this.creationDate = new DERGeneralizedTime(creationDate);
+ this.lastModifiedDate = new DERGeneralizedTime(lastModifiedDate);
+ this.data = new DEROctetString(Arrays.clone(data));
+ this.comment = comment;
+ }
+
+ public static ObjectData getInstance(
+ Object obj)
+ {
+ if (obj instanceof ObjectData)
+ {
+ return (ObjectData)obj;
+ }
+ else if (obj != null)
+ {
+ return new ObjectData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public String getComment()
+ {
+ return comment;
+ }
+
+ public ASN1GeneralizedTime getCreationDate()
+ {
+ return creationDate;
+ }
+
+ public byte[] getData()
+ {
+ return Arrays.clone(data.getOctets());
+ }
+
+ public String getIdentifier()
+ {
+ return identifier;
+ }
+
+ public ASN1GeneralizedTime getLastModifiedDate()
+ {
+ return lastModifiedDate;
+ }
+
+ public BigInteger getType()
+ {
+ return type;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(type));
+ v.add(new DERUTF8String(identifier));
+ v.add(creationDate);
+ v.add(lastModifiedDate);
+ v.add(data);
+
+ if (comment != null)
+ {
+ v.add(new DERUTF8String(comment));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java
new file mode 100644
index 00000000..f45ca151
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectDataSequence.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.asn1.bc;
+
+import java.util.Iterator;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ * ObjectDataSequence ::= SEQUENCE OF ObjectData
+ * </pre>
+ */
+public class ObjectDataSequence
+ extends ASN1Object
+ implements org.bouncycastle.util.Iterable<ASN1Encodable>
+{
+ private final ASN1Encodable[] dataSequence;
+
+ public ObjectDataSequence(ObjectData[] dataSequence)
+ {
+ this.dataSequence = new ASN1Encodable[dataSequence.length];
+
+ System.arraycopy(dataSequence, 0, this.dataSequence, 0, dataSequence.length);
+ }
+
+ private ObjectDataSequence(ASN1Sequence seq)
+ {
+ dataSequence = new ASN1Encodable[seq.size()];
+
+ for (int i = 0; i != dataSequence.length; i++)
+ {
+ dataSequence[i] = ObjectData.getInstance(seq.getObjectAt(i));
+ }
+ }
+
+ public static ObjectDataSequence getInstance(
+ Object obj)
+ {
+ if (obj instanceof ObjectDataSequence)
+ {
+ return (ObjectDataSequence)obj;
+ }
+ else if (obj != null)
+ {
+ return new ObjectDataSequence(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new DERSequence(dataSequence);
+ }
+
+ public Iterator<ASN1Encodable> iterator()
+ {
+ return new Arrays.Iterator<ASN1Encodable>(dataSequence);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java
new file mode 100644
index 00000000..ef2e773e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStore.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * <pre>
+ * ObjectStore ::= SEQUENCE {
+ * CHOICE {
+ * encryptedObjectStoreData EncryptedObjectStoreData,
+ * objectStoreData ObjectStoreData
+ * }
+ * integrityCheck ObjectStoreIntegrityCheck
+ * }
+ * </pre>
+ */
+public class ObjectStore
+ extends ASN1Object
+{
+ private final ASN1Encodable storeData;
+ private final ObjectStoreIntegrityCheck integrityCheck;
+
+ public ObjectStore(ObjectStoreData objectStoreData, ObjectStoreIntegrityCheck integrityCheck)
+ {
+ this.storeData = objectStoreData;
+ this.integrityCheck = integrityCheck;
+ }
+
+
+ public ObjectStore(EncryptedObjectStoreData encryptedObjectStoreData, ObjectStoreIntegrityCheck integrityCheck)
+ {
+ this.storeData = encryptedObjectStoreData;
+ this.integrityCheck = integrityCheck;
+ }
+
+ private ObjectStore(ASN1Sequence seq)
+ {
+ ASN1Encodable sData = seq.getObjectAt(0);
+ if (sData instanceof EncryptedObjectStoreData)
+ {
+ this.storeData = sData;
+ }
+ else if (sData instanceof ObjectStoreData)
+ {
+ this.storeData = sData;
+ }
+ else
+ {
+ ASN1Sequence seqData = ASN1Sequence.getInstance(sData);
+
+ if (seqData.size() == 2)
+ {
+ this.storeData = EncryptedObjectStoreData.getInstance(seqData);
+ }
+ else
+ {
+ this.storeData = ObjectStoreData.getInstance(seqData);
+ }
+ }
+
+ this.integrityCheck = ObjectStoreIntegrityCheck.getInstance(seq.getObjectAt(1));
+ }
+
+ public static ObjectStore getInstance(Object o)
+ {
+ if (o instanceof ObjectStore)
+ {
+ return (ObjectStore)o;
+ }
+ else if (o != null)
+ {
+ return new ObjectStore(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public ObjectStoreIntegrityCheck getIntegrityCheck()
+ {
+ return integrityCheck;
+ }
+
+ public ASN1Encodable getStoreData()
+ {
+ return storeData;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(storeData);
+ v.add(integrityCheck);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java
new file mode 100644
index 00000000..e9cc0a8f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreData.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1.bc;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <pre>
+ * ObjectStoreData ::= SEQUENCE {
+ * version INTEGER.
+ * dataSalt OCTET STRING,
+ * integrityAlgorithm AlgorithmIdentifier,
+ * creationDate GeneralizedTime,
+ * lastModifiedDate GeneralizedTime,
+ * objectDataSequence ObjectDataSequence,
+ * comment UTF8String OPTIONAL
+ * }
+ * </pre>
+ */
+public class ObjectStoreData
+ extends ASN1Object
+{
+ private final BigInteger version;
+ private final AlgorithmIdentifier integrityAlgorithm;
+ private final ASN1GeneralizedTime creationDate;
+ private final ASN1GeneralizedTime lastModifiedDate;
+ private final ObjectDataSequence objectDataSequence;
+ private final String comment;
+
+ public ObjectStoreData(AlgorithmIdentifier integrityAlgorithm, Date creationDate, Date lastModifiedDate, ObjectDataSequence objectDataSequence, String comment)
+ {
+ this.version = BigInteger.valueOf(1);
+ this.integrityAlgorithm = integrityAlgorithm;
+ this.creationDate = new DERGeneralizedTime(creationDate);
+ this.lastModifiedDate = new DERGeneralizedTime(lastModifiedDate);
+ this.objectDataSequence = objectDataSequence;
+ this.comment = comment;
+ }
+
+ private ObjectStoreData(ASN1Sequence seq)
+ {
+ this.version = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
+ this.integrityAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ this.creationDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2));
+ this.lastModifiedDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3));
+ this.objectDataSequence = ObjectDataSequence.getInstance(seq.getObjectAt(4));
+ this.comment = (seq.size() == 6) ? DERUTF8String.getInstance(seq.getObjectAt(5)).getString() : null;
+ }
+
+ public static ObjectStoreData getInstance(Object o)
+ {
+ if (o instanceof ObjectStoreData)
+ {
+ return (ObjectStoreData)o;
+ }
+ else if (o != null)
+ {
+ return new ObjectStoreData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public String getComment()
+ {
+ return comment;
+ }
+
+ public ASN1GeneralizedTime getCreationDate()
+ {
+ return creationDate;
+ }
+
+ public AlgorithmIdentifier getIntegrityAlgorithm()
+ {
+ return integrityAlgorithm;
+ }
+
+ public ASN1GeneralizedTime getLastModifiedDate()
+ {
+ return lastModifiedDate;
+ }
+
+ public ObjectDataSequence getObjectDataSequence()
+ {
+ return objectDataSequence;
+ }
+
+ public BigInteger getVersion()
+ {
+ return version;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(version));
+ v.add(integrityAlgorithm);
+ v.add(creationDate);
+ v.add(lastModifiedDate);
+ v.add(objectDataSequence);
+
+ if (comment != null)
+ {
+ v.add(new DERUTF8String(comment));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java
new file mode 100644
index 00000000..96c1b6fc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.asn1.bc;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+
+/**
+ * <pre>
+ * ObjectStoreIntegrityCheck ::= CHOICE {
+ * PbeMacIntegrityCheck
+ * }
+ * </pre>
+ */
+public class ObjectStoreIntegrityCheck
+ extends ASN1Object
+ implements ASN1Choice
+{
+ public static final int PBKD_MAC_CHECK = 0;
+
+ private final int type;
+ private final ASN1Object integrityCheck;
+
+ public ObjectStoreIntegrityCheck(PbkdMacIntegrityCheck macIntegrityCheck)
+ {
+ this((ASN1Encodable)macIntegrityCheck);
+ }
+
+ private ObjectStoreIntegrityCheck(ASN1Encodable obj)
+ {
+ if (obj instanceof ASN1Sequence || obj instanceof PbkdMacIntegrityCheck)
+ {
+ this.type = PBKD_MAC_CHECK;
+ this.integrityCheck = PbkdMacIntegrityCheck.getInstance(obj);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unknown check object in integrity check.");
+ }
+ }
+
+ public static ObjectStoreIntegrityCheck getInstance(Object o)
+ {
+ if (o instanceof ObjectStoreIntegrityCheck)
+ {
+ return (ObjectStoreIntegrityCheck)o;
+ }
+ else if (o instanceof byte[])
+ {
+ try
+ {
+ return new ObjectStoreIntegrityCheck(ASN1Primitive.fromByteArray((byte[])o));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Unable to parse integrity check details.");
+ }
+ }
+ else if (o != null)
+ {
+ return new ObjectStoreIntegrityCheck((ASN1Encodable)(o));
+ }
+
+ return null;
+ }
+
+
+ public int getType()
+ {
+ return type;
+ }
+
+ public ASN1Object getIntegrityCheck()
+ {
+ return integrityCheck;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return integrityCheck.toASN1Primitive();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java
new file mode 100644
index 00000000..f62e86ee
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ * PbkdMacIntegrityCheck ::= SEQUENCE {
+ * macAlgorithm AlgorithmIdentifier,
+ * pbkdAlgorithm KeyDerivationFunc,
+ * mac OCTET STRING
+ * }
+ * </pre>
+ */
+public class PbkdMacIntegrityCheck
+ extends ASN1Object
+{
+ private final AlgorithmIdentifier macAlgorithm;
+ private final KeyDerivationFunc pbkdAlgorithm;
+ private final ASN1OctetString mac;
+
+ public PbkdMacIntegrityCheck(AlgorithmIdentifier macAlgorithm, KeyDerivationFunc pbkdAlgorithm, byte[] mac)
+ {
+ this.macAlgorithm = macAlgorithm;
+ this.pbkdAlgorithm = pbkdAlgorithm;
+ this.mac = new DEROctetString(Arrays.clone(mac));
+ }
+
+ private PbkdMacIntegrityCheck(ASN1Sequence seq)
+ {
+ this.macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+ this.pbkdAlgorithm = KeyDerivationFunc.getInstance(seq.getObjectAt(1));
+ this.mac = ASN1OctetString.getInstance(seq.getObjectAt(2));
+ }
+
+ public static PbkdMacIntegrityCheck getInstance(Object o)
+ {
+ if (o instanceof PbkdMacIntegrityCheck)
+ {
+ return (PbkdMacIntegrityCheck)o;
+ }
+ else if (o != null)
+ {
+ return new PbkdMacIntegrityCheck(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getMacAlgorithm()
+ {
+ return macAlgorithm;
+ }
+
+ public KeyDerivationFunc getPbkdAlgorithm()
+ {
+ return pbkdAlgorithm;
+ }
+
+ public byte[] getMac()
+ {
+ return Arrays.clone(mac.getOctets());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(macAlgorithm);
+ v.add(pbkdAlgorithm);
+ v.add(mac);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java
new file mode 100644
index 00000000..2e27d012
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/SecretKeyData.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ * SecretKeyData ::= SEQUENCE {
+ * keyAlgorithm OBJECT IDENTIFIER,
+ * keyBytes OCTET STRING
+ * }
+ * </pre>
+ */
+public class SecretKeyData
+ extends ASN1Object
+{
+ private final ASN1ObjectIdentifier keyAlgorithm;
+ private final ASN1OctetString keyBytes;
+
+ public SecretKeyData(ASN1ObjectIdentifier keyAlgorithm, byte[] keyBytes)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.keyBytes = new DEROctetString(Arrays.clone(keyBytes));
+ }
+
+ private SecretKeyData(ASN1Sequence seq)
+ {
+ this.keyAlgorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+ this.keyBytes = ASN1OctetString.getInstance(seq.getObjectAt(1));
+ }
+
+ public static SecretKeyData getInstance(Object o)
+ {
+ if (o instanceof SecretKeyData)
+ {
+ return (SecretKeyData)o;
+ }
+ else if (o != null)
+ {
+ return new SecretKeyData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public byte[] getKeyBytes()
+ {
+ return Arrays.clone(keyBytes.getOctets());
+ }
+
+ public ASN1ObjectIdentifier getKeyAlgorithm()
+ {
+ return keyAlgorithm;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(keyAlgorithm);
+ v.add(keyBytes);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java b/bcprov/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java
index 3aa54579..608b532b 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java
@@ -46,6 +46,8 @@ public class EncryptedValue
case 4:
valueHint = ASN1OctetString.getInstance(tObj, false);
break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + tObj.getTagNo());
}
index++;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
index c6e8e0d1..d9bf7419 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
@@ -21,6 +21,9 @@ public interface CryptoProObjectIdentifiers
/** Gost R28147 OID: 1.2.643.2.2.21 */
static final ASN1ObjectIdentifier gostR28147_gcfb = GOST_id.branch("21");
+ /** Gost R28147-89-CryotoPro-A-ParamSet OID: 1.2.643.2.2.31.0 */
+ static final ASN1ObjectIdentifier id_Gost28147_89_CryptoPro_TestParamSet = GOST_id.branch("31.0");
+
/** Gost R28147-89-CryotoPro-A-ParamSet OID: 1.2.643.2.2.31.1 */
static final ASN1ObjectIdentifier id_Gost28147_89_CryptoPro_A_ParamSet = GOST_id.branch("31.1");
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java
index 124bca66..368907ed 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java
@@ -10,6 +10,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
/**
* ASN.1 algorithm identifier parameters for GOST-28147
@@ -93,6 +94,6 @@ public class GOST28147Parameters
*/
public byte[] getIV()
{
- return iv.getOctets();
+ return Arrays.clone(iv.getOctets());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
index cc95571f..d7b77b85 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
@@ -70,12 +70,15 @@ public class DVCSCertInfo
{
int i = 0;
ASN1Encodable x = seq.getObjectAt(i++);
- if (x instanceof ASN1Integer)
+ try
{
ASN1Integer encVersion = ASN1Integer.getInstance(x);
this.version = encVersion.getValue().intValue();
x = seq.getObjectAt(i++);
}
+ catch (IllegalArgumentException e)
+ {
+ }
this.dvReqInfo = DVCSRequestInformation.getInstance(x);
x = seq.getObjectAt(i++);
@@ -90,7 +93,7 @@ public class DVCSCertInfo
x = seq.getObjectAt(i++);
- try
+ if (x instanceof ASN1TaggedObject)
{
ASN1TaggedObject t = ASN1TaggedObject.getInstance(x);
int tagNo = t.getTagNo();
@@ -109,13 +112,11 @@ public class DVCSCertInfo
case TAG_CERTS:
this.certs = ASN1Sequence.getInstance(t, false);
break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + tagNo);
}
continue;
-
- }
- catch (IllegalArgumentException e)
- {
}
try
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
index 8d28f93d..79d58051 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
@@ -102,6 +102,8 @@ public class DVCSRequestInformation
case TAG_EXTENSIONS:
this.extensions = Extensions.getInstance(t, false);
break;
+ default:
+ throw new IllegalArgumentException("unknown tag number encountered: " + tagNo);
}
}
else
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
index aeb3c2cf..1d67a10c 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
@@ -21,9 +21,8 @@ public class DVCSTime
extends ASN1Object
implements ASN1Choice
{
- private ASN1GeneralizedTime genTime;
- private ContentInfo timeStampToken;
- private Date time;
+ private final ASN1GeneralizedTime genTime;
+ private final ContentInfo timeStampToken;
// constructors:
@@ -35,10 +34,12 @@ public class DVCSTime
public DVCSTime(ASN1GeneralizedTime genTime)
{
this.genTime = genTime;
+ this.timeStampToken = null;
}
public DVCSTime(ContentInfo timeStampToken)
{
+ this.genTime = null;
this.timeStampToken = timeStampToken;
}
@@ -82,18 +83,14 @@ public class DVCSTime
public ASN1Primitive toASN1Primitive()
{
-
if (genTime != null)
{
return genTime;
}
-
- if (timeStampToken != null)
+ else
{
return timeStampToken.toASN1Primitive();
}
-
- return null;
}
public String toString()
@@ -102,10 +99,9 @@ public class DVCSTime
{
return genTime.toString();
}
- if (timeStampToken != null)
+ else
{
return timeStampToken.toString();
}
- return null;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
index 3123f40c..a1e32aa1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
@@ -1,5 +1,10 @@
+/***************************************************************/
+/****** DO NOT EDIT THIS CLASS bc-java SOURCE FILE ******/
+/***************************************************************/
package org.bouncycastle.asn1.dvcs;
+import java.util.Arrays;
+
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
@@ -89,6 +94,9 @@ public class PathProcInput
case 1:
x = ASN1Boolean.getInstance(t, false);
result.setInhibitAnyPolicy(x.isTrue());
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + t.getTagNo());
}
}
}
@@ -119,15 +127,15 @@ public class PathProcInput
if (inhibitPolicyMapping)
{
- v.add(new ASN1Boolean(inhibitPolicyMapping));
+ v.add(ASN1Boolean.getInstance(inhibitPolicyMapping));
}
if (explicitPolicyReqd)
{
- v.add(new DERTaggedObject(false, 0, new ASN1Boolean(explicitPolicyReqd)));
+ v.add(new DERTaggedObject(false, 0, ASN1Boolean.getInstance(explicitPolicyReqd)));
}
if (inhibitAnyPolicy)
{
- v.add(new DERTaggedObject(false, 1, new ASN1Boolean(inhibitAnyPolicy)));
+ v.add(new DERTaggedObject(false, 1, ASN1Boolean.getInstance(inhibitAnyPolicy)));
}
return new DERSequence(v);
@@ -136,7 +144,7 @@ public class PathProcInput
public String toString()
{
return "PathProcInput: {\n" +
- "acceptablePolicySet: " + acceptablePolicySet + "\n" +
+ "acceptablePolicySet: " + Arrays.asList(acceptablePolicySet) + "\n" +
"inhibitPolicyMapping: " + inhibitPolicyMapping + "\n" +
"explicitPolicyReqd: " + explicitPolicyReqd + "\n" +
"inhibitAnyPolicy: " + inhibitAnyPolicy + "\n" +
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
index ec3caadf..3dc1a276 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
@@ -60,35 +60,35 @@ public class TargetEtcChain
ASN1Encodable obj = seq.getObjectAt(i++);
this.target = CertEtcToken.getInstance(obj);
- try
+ if (seq.size() > 1)
{
obj = seq.getObjectAt(i++);
- this.chain = ASN1Sequence.getInstance(obj);
- }
- catch (IllegalArgumentException e)
- {
- }
- catch (IndexOutOfBoundsException e)
- {
- return;
- }
-
- try
- {
- obj = seq.getObjectAt(i++);
- ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
- switch (tagged.getTagNo())
+ if (obj instanceof ASN1TaggedObject)
{
- case 0:
- this.pathProcInput = PathProcInput.getInstance(tagged, false);
- break;
+ extractPathProcInput(obj);
+ }
+ else
+ {
+ this.chain = ASN1Sequence.getInstance(obj);
+ if (seq.size() > 2)
+ {
+ obj = seq.getObjectAt(i);
+ extractPathProcInput(obj);
+ }
}
}
- catch (IllegalArgumentException e)
- {
- }
- catch (IndexOutOfBoundsException e)
+ }
+
+ private void extractPathProcInput(ASN1Encodable obj)
+ {
+ ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
+ switch (tagged.getTagNo())
{
+ case 0:
+ this.pathProcInput = PathProcInput.getInstance(tagged, false);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + tagged.getTagNo());
}
}
@@ -162,21 +162,11 @@ public class TargetEtcChain
return null;
}
- private void setChain(ASN1Sequence chain)
- {
- this.chain = chain;
- }
-
public PathProcInput getPathProcInput()
{
return pathProcInput;
}
- private void setPathProcInput(PathProcInput pathProcInput)
- {
- this.pathProcInput = pathProcInput;
- }
-
public static TargetEtcChain[] arrayFromSequence(ASN1Sequence seq)
{
TargetEtcChain[] tmp = new TargetEtcChain[seq.size()];
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java
index 22391409..8cd3ae60 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java
@@ -72,6 +72,7 @@ public class CVCertificate
throw new IOException("Invalid Object, not an Iso7816CertificateStructure");
}
}
+ content.close();
}
else
{
@@ -137,7 +138,7 @@ public class CVCertificate
throws IOException
{
certificateBody = body;
- this.signature = signature;
+ this.signature = Arrays.clone(signature);
// patch remi
valid |= bodyValid;
valid |= signValid;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java
index 74c6c1ff..c07deba3 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java
@@ -6,16 +6,13 @@ import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1ApplicationSpecific;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1ParsingException;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERApplicationSpecific;
import org.bouncycastle.asn1.DEROctetString;
-
-//import java.math.BigInteger;
-
+import org.bouncycastle.util.Arrays;
public class CVCertificateRequest
extends ASN1Object
@@ -25,10 +22,8 @@ public class CVCertificateRequest
private byte[] innerSignature = null;
private byte[] outerSignature = null;
- private int valid;
-
- private static int bodyValid = 0x01;
- private static int signValid = 0x02;
+ private static final int bodyValid = 0x01;
+ private static final int signValid = 0x02;
private CVCertificateRequest(ASN1ApplicationSpecific request)
throws IOException
@@ -52,6 +47,7 @@ public class CVCertificateRequest
{
if (request.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE)
{
+ int valid = 0;
ASN1Sequence seq = ASN1Sequence.getInstance(request.getObject(BERTags.SEQUENCE));
for (Enumeration en = seq.getObjects(); en.hasMoreElements();)
{
@@ -70,6 +66,10 @@ public class CVCertificateRequest
throw new IOException("Invalid tag, not an CV Certificate Request element:" + obj.getApplicationTag());
}
}
+ if ((valid & (bodyValid | signValid)) == 0)
+ {
+ throw new IOException("Invalid CARDHOLDER_CERTIFICATE in request:" + request.getApplicationTag());
+ }
}
else
{
@@ -98,18 +98,6 @@ public class CVCertificateRequest
return null;
}
- ASN1ObjectIdentifier signOid = null;
- ASN1ObjectIdentifier keyOid = null;
-
- public static byte[] ZeroArray = new byte[]{0};
-
-
- String strCertificateHolderReference;
-
- byte[] encodedAuthorityReference;
-
- int ProfileId;
-
/**
* Returns the body of the certificate template
*
@@ -131,26 +119,19 @@ public class CVCertificateRequest
public byte[] getInnerSignature()
{
- return innerSignature;
+ return Arrays.clone(innerSignature);
}
public byte[] getOuterSignature()
{
- return outerSignature;
+ return Arrays.clone(outerSignature);
}
- byte[] certificate = null;
- protected String overSignerReference = null;
-
public boolean hasOuterSignature()
{
return outerSignature != null;
}
- byte[] encoded;
-
- PublicKeyDataObject iso7816PubKey = null;
-
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java
index 5f73f192..01a21a15 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java
@@ -115,6 +115,7 @@ public class CertificateBody
throw new IOException("Not a valid iso7816 DERApplicationSpecific tag " + aSpe.getApplicationTag());
}
}
+ aIS.close();
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
index 077807f2..255cf233 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
@@ -12,6 +12,7 @@ import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.util.Arrays;
/**
* an Iso7816ECDSAPublicKeyStructure structure.
@@ -129,7 +130,7 @@ public class ECDSAPublicKey
{
if ((options & G) != 0)
{
- return basePointG;
+ return Arrays.clone(basePointG);
}
else
{
@@ -258,7 +259,7 @@ public class ECDSAPublicKey
{
if ((options & Y) != 0)
{
- return publicPointY;
+ return Arrays.clone(publicPointY);
}
else
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
index e19c96f1..143040ba 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
@@ -119,6 +119,6 @@ public class PackedDate
public byte[] getEncoding()
{
- return time;
+ return Arrays.clone(time);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java b/bcprov/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
index 39539f34..ff14ea9b 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
@@ -45,7 +46,7 @@ public class CrlOcspRef
Enumeration e = seq.getObjects();
while (e.hasMoreElements())
{
- DERTaggedObject o = (DERTaggedObject)e.nextElement();
+ ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement();
switch (o.getTagNo())
{
case 0:
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java b/bcprov/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
index 9ff41131..4e3a1475 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
@@ -51,7 +52,7 @@ public class RevocationValues
Enumeration e = seq.getObjects();
while (e.hasMoreElements())
{
- DERTaggedObject o = (DERTaggedObject)e.nextElement();
+ ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement();
switch (o.getTagNo())
{
case 0:
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java b/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java
index ecc4db3c..d8510803 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java
@@ -88,7 +88,11 @@ public class SignerAttribute
*/
public Object[] getValues()
{
- return values;
+ Object[] rv = new Object[values.length];
+
+ System.arraycopy(values, 0, rv, 0, rv.length);
+
+ return rv;
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java b/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
index fcdb3206..579fe806 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
@@ -37,7 +38,7 @@ public class SignerLocation
while (e.hasMoreElements())
{
- DERTaggedObject o = (DERTaggedObject)e.nextElement();
+ ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement();
switch (o.getTagNo())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java b/bcprov/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java
index b511f2c2..ffc1f9fa 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java
@@ -10,6 +10,7 @@ import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.IssuerSerial;
+import org.bouncycastle.util.Arrays;
public class ESSCertIDv2
extends ASN1Object
@@ -97,7 +98,7 @@ public class ESSCertIDv2
this.hashAlgorithm = algId;
}
- this.certHash = certHash;
+ this.certHash = Arrays.clone(certHash);
this.issuerSerial = issuerSerial;
}
@@ -108,7 +109,7 @@ public class ESSCertIDv2
public byte[] getCertHash()
{
- return certHash;
+ return Arrays.clone(certHash);
}
public IssuerSerial getIssuerSerial()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java
index b7795a7e..64575a81 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java
@@ -61,7 +61,7 @@ public class LDSVersionInfo
* unicodeVersion PRINTABLE STRING
* }
* </pre>
- * @return a DERSequence representing the value in this object.
+ * @return an ASN.1 primitive composition of this LDSVersionInfo.
*/
public ASN1Primitive toASN1Primitive()
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
index 715e4bb9..99ddc5e4 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
@@ -8,6 +8,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
public class CAST5CBCParameters
extends ASN1Object
@@ -34,7 +35,7 @@ public class CAST5CBCParameters
byte[] iv,
int keyLength)
{
- this.iv = new DEROctetString(iv);
+ this.iv = new DEROctetString(Arrays.clone(iv));
this.keyLength = new ASN1Integer(keyLength);
}
@@ -47,7 +48,7 @@ public class CAST5CBCParameters
public byte[] getIV()
{
- return iv.getOctets();
+ return Arrays.clone(iv.getOctets());
}
public int getKeyLength()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
index 35b0f244..1c1d2768 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
@@ -7,6 +7,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
public class IDEACBCPar
extends ASN1Object
@@ -51,7 +52,7 @@ public class IDEACBCPar
{
if (iv != null)
{
- return iv.getOctets();
+ return Arrays.clone(iv.getOctets());
}
else
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
index 19077e4c..ba7e5187 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
@@ -17,38 +17,42 @@ public class NISTNamedCurves
static final Hashtable objIds = new Hashtable();
static final Hashtable names = new Hashtable();
- static void defineCurveAlias(String name, ASN1ObjectIdentifier oid)
+ static void defineCurve(String name, ASN1ObjectIdentifier oid)
{
- objIds.put(name.toUpperCase(), oid);
+ objIds.put(name, oid);
names.put(oid, name);
}
static
{
- defineCurveAlias("B-163", SECObjectIdentifiers.sect163r2);
- defineCurveAlias("B-233", SECObjectIdentifiers.sect233r1);
- defineCurveAlias("B-283", SECObjectIdentifiers.sect283r1);
- defineCurveAlias("B-409", SECObjectIdentifiers.sect409r1);
- defineCurveAlias("B-571", SECObjectIdentifiers.sect571r1);
-
- defineCurveAlias("K-163", SECObjectIdentifiers.sect163k1);
- defineCurveAlias("K-233", SECObjectIdentifiers.sect233k1);
- defineCurveAlias("K-283", SECObjectIdentifiers.sect283k1);
- defineCurveAlias("K-409", SECObjectIdentifiers.sect409k1);
- defineCurveAlias("K-571", SECObjectIdentifiers.sect571k1);
-
- defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1);
- defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1);
- defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1);
- defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1);
- defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1);
+ defineCurve("B-571", SECObjectIdentifiers.sect571r1);
+ defineCurve("B-409", SECObjectIdentifiers.sect409r1);
+ defineCurve("B-283", SECObjectIdentifiers.sect283r1);
+ defineCurve("B-233", SECObjectIdentifiers.sect233r1);
+ defineCurve("B-163", SECObjectIdentifiers.sect163r2);
+ defineCurve("K-571", SECObjectIdentifiers.sect571k1);
+ defineCurve("K-409", SECObjectIdentifiers.sect409k1);
+ defineCurve("K-283", SECObjectIdentifiers.sect283k1);
+ defineCurve("K-233", SECObjectIdentifiers.sect233k1);
+ defineCurve("K-163", SECObjectIdentifiers.sect163k1);
+ defineCurve("P-521", SECObjectIdentifiers.secp521r1);
+ defineCurve("P-384", SECObjectIdentifiers.secp384r1);
+ defineCurve("P-256", SECObjectIdentifiers.secp256r1);
+ defineCurve("P-224", SECObjectIdentifiers.secp224r1);
+ defineCurve("P-192", SECObjectIdentifiers.secp192r1);
}
public static X9ECParameters getByName(
String name)
{
- ASN1ObjectIdentifier oid = getOID(name);
- return oid == null ? null : getByOID(oid);
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
}
/**
@@ -90,6 +94,6 @@ public class NISTNamedCurves
*/
public static Enumeration getNames()
{
- return names.elements();
+ return objIds.keys();
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
index 0de40f20..49c0e6d7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -40,9 +40,17 @@ public interface NISTObjectIdentifiers
/** 2.16.840.1.101.3.4.2.10 */
static final ASN1ObjectIdentifier id_sha3_512 = hashAlgs.branch("10");
/** 2.16.840.1.101.3.4.2.11 */
- static final ASN1ObjectIdentifier id_shake128 = hashAlgs.branch("11");
+ static final ASN1ObjectIdentifier id_shake128 = hashAlgs.branch("11");
/** 2.16.840.1.101.3.4.2.12 */
- static final ASN1ObjectIdentifier id_shake256 = hashAlgs.branch("12");
+ static final ASN1ObjectIdentifier id_shake256 = hashAlgs.branch("12");
+ /** 2.16.840.1.101.3.4.2.13 */
+ static final ASN1ObjectIdentifier id_hmacWithSHA3_224 = hashAlgs.branch("13");
+ /** 2.16.840.1.101.3.4.2.14 */
+ static final ASN1ObjectIdentifier id_hmacWithSHA3_256 = hashAlgs.branch("14");
+ /** 2.16.840.1.101.3.4.2.15 */
+ static final ASN1ObjectIdentifier id_hmacWithSHA3_384 = hashAlgs.branch("15");
+ /** 2.16.840.1.101.3.4.2.16 */
+ static final ASN1ObjectIdentifier id_hmacWithSHA3_512 = hashAlgs.branch("16");
/** 2.16.840.1.101.3.4.1 */
static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1");
@@ -61,7 +69,9 @@ public interface NISTObjectIdentifiers
static final ASN1ObjectIdentifier id_aes128_GCM = aes.branch("6");
/** 2.16.840.1.101.3.4.1.7 */
static final ASN1ObjectIdentifier id_aes128_CCM = aes.branch("7");
-
+ /** 2.16.840.1.101.3.4.1.28 */
+ static final ASN1ObjectIdentifier id_aes128_wrap_pad = aes.branch("8");
+
/** 2.16.840.1.101.3.4.1.21 */
static final ASN1ObjectIdentifier id_aes192_ECB = aes.branch("21");
/** 2.16.840.1.101.3.4.1.22 */
@@ -76,7 +86,9 @@ public interface NISTObjectIdentifiers
static final ASN1ObjectIdentifier id_aes192_GCM = aes.branch("26");
/** 2.16.840.1.101.3.4.1.27 */
static final ASN1ObjectIdentifier id_aes192_CCM = aes.branch("27");
-
+ /** 2.16.840.1.101.3.4.1.28 */
+ static final ASN1ObjectIdentifier id_aes192_wrap_pad = aes.branch("28");
+
/** 2.16.840.1.101.3.4.1.41 */
static final ASN1ObjectIdentifier id_aes256_ECB = aes.branch("41");
/** 2.16.840.1.101.3.4.1.42 */
@@ -91,19 +103,51 @@ public interface NISTObjectIdentifiers
static final ASN1ObjectIdentifier id_aes256_GCM = aes.branch("46");
/** 2.16.840.1.101.3.4.1.47 */
static final ASN1ObjectIdentifier id_aes256_CCM = aes.branch("47");
+ /** 2.16.840.1.101.3.4.1.48 */
+ static final ASN1ObjectIdentifier id_aes256_wrap_pad = aes.branch("48");
//
// signatures
//
/** 2.16.840.1.101.3.4.3 */
- static final ASN1ObjectIdentifier id_dsa_with_sha2 = nistAlgorithm.branch("3");
+ static final ASN1ObjectIdentifier sigAlgs = nistAlgorithm.branch("3");
+
+ static final ASN1ObjectIdentifier id_dsa_with_sha2 = sigAlgs;
/** 2.16.840.1.101.3.4.3.1 */
- static final ASN1ObjectIdentifier dsa_with_sha224 = id_dsa_with_sha2.branch("1");
+ static final ASN1ObjectIdentifier dsa_with_sha224 = sigAlgs.branch("1");
/** 2.16.840.1.101.3.4.3.2 */
- static final ASN1ObjectIdentifier dsa_with_sha256 = id_dsa_with_sha2.branch("2");
+ static final ASN1ObjectIdentifier dsa_with_sha256 = sigAlgs.branch("2");
/** 2.16.840.1.101.3.4.3.3 */
- static final ASN1ObjectIdentifier dsa_with_sha384 = id_dsa_with_sha2.branch("3");
+ static final ASN1ObjectIdentifier dsa_with_sha384 = sigAlgs.branch("3");
/** 2.16.840.1.101.3.4.3.4 */
- static final ASN1ObjectIdentifier dsa_with_sha512 = id_dsa_with_sha2.branch("4");
+ static final ASN1ObjectIdentifier dsa_with_sha512 = sigAlgs.branch("4");
+ /** 2.16.840.1.101.3.4.3.5 */
+ static final ASN1ObjectIdentifier id_dsa_with_sha3_224 = sigAlgs.branch("5");
+ /** 2.16.840.1.101.3.4.3.6 */
+ static final ASN1ObjectIdentifier id_dsa_with_sha3_256 = sigAlgs.branch("6");
+ /** 2.16.840.1.101.3.4.3.7 */
+ static final ASN1ObjectIdentifier id_dsa_with_sha3_384 = sigAlgs.branch("7");
+ /** 2.16.840.1.101.3.4.3.8 */
+ static final ASN1ObjectIdentifier id_dsa_with_sha3_512 = sigAlgs.branch("8");
+
+ // ECDSA with SHA-3
+ /** 2.16.840.1.101.3.4.3.9 */
+ static final ASN1ObjectIdentifier id_ecdsa_with_sha3_224 = sigAlgs.branch("9");
+ /** 2.16.840.1.101.3.4.3.10 */
+ static final ASN1ObjectIdentifier id_ecdsa_with_sha3_256 = sigAlgs.branch("10");
+ /** 2.16.840.1.101.3.4.3.11 */
+ static final ASN1ObjectIdentifier id_ecdsa_with_sha3_384 = sigAlgs.branch("11");
+ /** 2.16.840.1.101.3.4.3.12 */
+ static final ASN1ObjectIdentifier id_ecdsa_with_sha3_512 = sigAlgs.branch("12");
+
+ // RSA PKCS #1 v1.5 Signature with SHA-3 family.
+ /** 2.16.840.1.101.3.4.3.9 */
+ static final ASN1ObjectIdentifier id_rsassa_pkcs1_v1_5_with_sha3_224 = sigAlgs.branch("13");
+ /** 2.16.840.1.101.3.4.3.10 */
+ static final ASN1ObjectIdentifier id_rsassa_pkcs1_v1_5_with_sha3_256 = sigAlgs.branch("14");
+ /** 2.16.840.1.101.3.4.3.11 */
+ static final ASN1ObjectIdentifier id_rsassa_pkcs1_v1_5_with_sha3_384 = sigAlgs.branch("15");
+ /** 2.16.840.1.101.3.4.3.12 */
+ static final ASN1ObjectIdentifier id_rsassa_pkcs1_v1_5_with_sha3_512 = sigAlgs.branch("16");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java
index af530ae5..0b1db325 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java
@@ -13,7 +13,7 @@ public class CertStatus
implements ASN1Choice
{
private int tagNo;
- private ASN1Encodable value;
+ private ASN1Encodable value;
/**
* create a CertStatus object with a tag of zero.
@@ -39,7 +39,7 @@ public class CertStatus
this.value = value;
}
- public CertStatus(
+ private CertStatus(
ASN1TaggedObject choice)
{
this.tagNo = choice.getTagNo();
@@ -54,6 +54,9 @@ public class CertStatus
break;
case 2:
value = DERNull.INSTANCE;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + choice.getTagNo());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
index 747277c3..49b2652c 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
@@ -22,7 +23,7 @@ public class CRLBag
ASN1Sequence seq)
{
this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
- this.crlValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+ this.crlValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject();
}
public static CRLBag getInstance(Object o)
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
index fb418aeb..dca0719c 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x500.X500Name;
@@ -116,7 +117,7 @@ public class CertificationRequestInfo
//
if (seq.size() > 3)
{
- DERTaggedObject tagobj = (DERTaggedObject)seq.getObjectAt(3);
+ ASN1TaggedObject tagobj = (ASN1TaggedObject)seq.getObjectAt(3);
attributes = ASN1Set.getInstance(tagobj, false);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
index 1d8f582c..63fa2e4e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
@@ -11,6 +11,7 @@ import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.util.Arrays;
public class MacData
extends ASN1Object
@@ -41,7 +42,7 @@ public class MacData
{
this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0));
- this.salt = ((ASN1OctetString)seq.getObjectAt(1)).getOctets();
+ this.salt = Arrays.clone(((ASN1OctetString)seq.getObjectAt(1)).getOctets());
if (seq.size() == 3)
{
@@ -59,7 +60,7 @@ public class MacData
int iterationCount)
{
this.digInfo = digInfo;
- this.salt = salt;
+ this.salt = Arrays.clone(salt);
this.iterationCount = BigInteger.valueOf(iterationCount);
}
@@ -70,7 +71,7 @@ public class MacData
public byte[] getSalt()
{
- return salt;
+ return Arrays.clone(salt);
}
public BigInteger getIterationCount()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
index 8e8f00f8..ba222748 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -39,6 +39,10 @@ public interface PKCSObjectIdentifiers
static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13");
/** PKCS#1: 1.2.840.113549.1.1.14 */
static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14");
+ /** PKCS#1: 1.2.840.113549.1.1.15 */
+ ASN1ObjectIdentifier sha512_224WithRSAEncryption = pkcs_1.branch("15");
+ /** PKCS#1: 1.2.840.113549.1.1.16 */
+ ASN1ObjectIdentifier sha512_256WithRSAEncryption = pkcs_1.branch("16");
//
// pkcs-3 OBJECT IDENTIFIER ::= {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java
new file mode 100644
index 00000000..f4dfe43f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java
@@ -0,0 +1,28 @@
+package org.bouncycastle.asn1.rosstandart;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface RosstandartObjectIdentifiers
+{
+ static final ASN1ObjectIdentifier rosstandart = new ASN1ObjectIdentifier("1.2.643.7");
+
+ static final ASN1ObjectIdentifier id_tc26 = rosstandart.branch("1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3411_12_256 = id_tc26.branch("1.2.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3411_12_512 = id_tc26.branch("1.2.3");
+
+ static final ASN1ObjectIdentifier id_tc26_hmac_gost_3411_12_256 = id_tc26.branch("1.4.1");
+
+ static final ASN1ObjectIdentifier id_tc26_hmac_gost_3411_12_512 = id_tc26.branch("1.4.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSetA = id_tc26.branch("2.1.1.1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetA = id_tc26.branch("2.1.2.1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetB = id_tc26.branch("2.1.2.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetC = id_tc26.branch("2.1.2.3");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_28147_param_Z = id_tc26.branch("2.5.1.1");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
index 1cdaf129..1d2c78cb 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -987,7 +987,7 @@ public class SECNamedCurves
static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
{
- objIds.put(name.toLowerCase(), oid);
+ objIds.put(name, oid);
names.put(oid, name);
curves.put(oid, holder);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java
index 0bb79bb8..121cc2f2 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java
@@ -13,7 +13,7 @@ import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
/**
- * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+ * Elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
* http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
*/
public class TeleTrusTNamedCurves
@@ -307,34 +307,40 @@ public class TeleTrusTNamedCurves
static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
{
- objIds.put(name.toLowerCase(), oid);
+ objIds.put(name, oid);
names.put(oid, name);
curves.put(oid, holder);
}
static
{
- defineCurve("brainpoolP160r1", TeleTrusTObjectIdentifiers.brainpoolP160r1, brainpoolP160r1);
- defineCurve("brainpoolP160t1", TeleTrusTObjectIdentifiers.brainpoolP160t1, brainpoolP160t1);
- defineCurve("brainpoolP192r1", TeleTrusTObjectIdentifiers.brainpoolP192r1, brainpoolP192r1);
- defineCurve("brainpoolP192t1", TeleTrusTObjectIdentifiers.brainpoolP192t1, brainpoolP192t1);
- defineCurve("brainpoolP224r1", TeleTrusTObjectIdentifiers.brainpoolP224r1, brainpoolP224r1);
- defineCurve("brainpoolP224t1", TeleTrusTObjectIdentifiers.brainpoolP224t1, brainpoolP224t1);
- defineCurve("brainpoolP256r1", TeleTrusTObjectIdentifiers.brainpoolP256r1, brainpoolP256r1);
- defineCurve("brainpoolP256t1", TeleTrusTObjectIdentifiers.brainpoolP256t1, brainpoolP256t1);
- defineCurve("brainpoolP320r1", TeleTrusTObjectIdentifiers.brainpoolP320r1, brainpoolP320r1);
- defineCurve("brainpoolP320t1", TeleTrusTObjectIdentifiers.brainpoolP320t1, brainpoolP320t1);
- defineCurve("brainpoolP384r1", TeleTrusTObjectIdentifiers.brainpoolP384r1, brainpoolP384r1);
- defineCurve("brainpoolP384t1", TeleTrusTObjectIdentifiers.brainpoolP384t1, brainpoolP384t1);
- defineCurve("brainpoolP512r1", TeleTrusTObjectIdentifiers.brainpoolP512r1, brainpoolP512r1);
- defineCurve("brainpoolP512t1", TeleTrusTObjectIdentifiers.brainpoolP512t1, brainpoolP512t1);
+ defineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.brainpoolP160r1, brainpoolP160r1);
+ defineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.brainpoolP160t1, brainpoolP160t1);
+ defineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.brainpoolP192r1, brainpoolP192r1);
+ defineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.brainpoolP192t1, brainpoolP192t1);
+ defineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.brainpoolP224r1, brainpoolP224r1);
+ defineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.brainpoolP224t1, brainpoolP224t1);
+ defineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.brainpoolP256r1, brainpoolP256r1);
+ defineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.brainpoolP256t1, brainpoolP256t1);
+ defineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.brainpoolP320r1, brainpoolP320r1);
+ defineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.brainpoolP320t1, brainpoolP320t1);
+ defineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.brainpoolP384r1, brainpoolP384r1);
+ defineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.brainpoolP384t1, brainpoolP384t1);
+ defineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.brainpoolP512r1, brainpoolP512r1);
+ defineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.brainpoolP512t1, brainpoolP512t1);
}
public static X9ECParameters getByName(
String name)
{
- ASN1ObjectIdentifier oid = getOID(name);
- return oid == null ? null : getByOID(oid);
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
}
/**
@@ -347,7 +353,13 @@ public class TeleTrusTNamedCurves
ASN1ObjectIdentifier oid)
{
X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
- return holder == null ? null : holder.getParameters();
+
+ if (holder != null)
+ {
+ return holder.getParameters();
+ }
+
+ return null;
}
/**
@@ -377,7 +389,7 @@ public class TeleTrusTNamedCurves
*/
public static Enumeration getNames()
{
- return names.elements();
+ return objIds.keys();
}
public static ASN1ObjectIdentifier getOID(short curvesize, boolean twisted)
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
index 2be7efec..c38eac74 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -3,9 +3,11 @@ package org.bouncycastle.asn1.teletrust;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
/**
+ * Object identifiers based on the TeleTrust branch.
+ * <pre>
* TeleTrusT:
* { iso(1) identifier-organization(3) teleTrust(36) algorithm(3)
- *
+ * </pre>
*/
public interface TeleTrusTObjectIdentifiers
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/test/BitStringTest.java b/bcprov/src/main/java/org/bouncycastle/asn1/test/BitStringTest.java
index ecc4c834..4c49f326 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/test/BitStringTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/test/BitStringTest.java
@@ -2,9 +2,11 @@ package org.bouncycastle.asn1.test;
import java.io.IOException;
+import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DLBitString;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
@@ -100,10 +102,24 @@ public class BitStringTest
{
fail("failed DL check");
}
+ ASN1BitString dl = DLBitString.getInstance(dlData);
+
+ isTrue("DL test failed", dl instanceof DLBitString);
if (!Arrays.areEqual(derData, ASN1Primitive.fromByteArray(dlData).getEncoded(ASN1Encoding.DER)))
{
fail("failed DER check");
}
+ try
+ {
+ DERBitString.getInstance(dlData);
+ fail("no exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // ignore
+ }
+ ASN1BitString der = DERBitString.getInstance(derData);
+ isTrue("DER test failed", der instanceof DERBitString);
}
public void performTest()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/test/MiscTest.java b/bcprov/src/main/java/org/bouncycastle/asn1/test/MiscTest.java
index 21dcd0fa..8dbb852f 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/test/MiscTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/test/MiscTest.java
@@ -5,7 +5,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.BERSequence;
@@ -67,6 +69,46 @@ public class MiscTest
}
}
+ public void derIntegerTest()
+ throws Exception
+ {
+ try
+ {
+ new ASN1Integer(new byte[] { 0, 0, 0, 1});
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("wrong exc", "malformed integer".equals(e.getMessage()));
+ }
+
+ try
+ {
+ new ASN1Integer(new byte[] {(byte)0xff, (byte)0x80, 0, 1});
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("wrong exc", "malformed integer".equals(e.getMessage()));
+ }
+
+ try
+ {
+ new ASN1Enumerated(new byte[] { 0, 0, 0, 1});
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("wrong exc", "malformed enumerated".equals(e.getMessage()));
+ }
+
+ try
+ {
+ new ASN1Enumerated(new byte[] {(byte)0xff, (byte)0x80, 0, 1});
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("wrong exc", "malformed enumerated".equals(e.getMessage()));
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -115,6 +157,7 @@ public class MiscTest
}
shouldFailOnExtraData();
+ derIntegerTest();
}
public String getName()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java b/bcprov/src/main/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java
index bd665ecd..9f74425b 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/test/ObjectIdentifierTest.java
@@ -16,13 +16,60 @@ public class ObjectIdentifierTest
throws Exception
{
// exercise the object cache
- for (int i = 0; i < 1024; i++)
+ for (int i = 0; i < 100; i++)
{
- for (int j = 0; j != 17000; j++)
+ for (int j = 0; j < 100; j++)
{
- byte[] encoded = new ASN1ObjectIdentifier("1.1." + i + "." + j).getEncoded();
+ final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1." + i + "." + j);
+ final byte[] encoded1 = oid1.getEncoded();
+ final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1);
+ if (oid1 == oid2)
+ {
+ fail("Shouldn't be the same: " + oid1 + " " + oid2);
+ }
+ if (!oid1.equals(oid2))
+ {
+ fail("Should be equal: " + oid1 + " " + oid2);
+ }
+ final ASN1ObjectIdentifier oid3 = oid2.intern();
+ if (oid2 != oid3)
+ {
+ fail("Should be the same: " + oid2 + " " + oid3);
+ }
+ if (!oid2.equals(oid3))
+ {
+ fail("Should be equal: " + oid2 + " " + oid3);
+ }
+ final byte[] encoded2 = oid3.getEncoded();
+ final ASN1ObjectIdentifier oid4 = ASN1ObjectIdentifier.getInstance(encoded2);
+ if (oid3 != oid4)
+ {
+ fail("Should be taken from cache: " + oid3 + " " + oid4);
+ }
+ if (!oid3.equals(oid4))
+ {
+ fail("Should be equal: " + oid3 + " " + oid4);
+ }
+ }
+ }
- ASN1ObjectIdentifier.getInstance(encoded);
+ // make sure we're not leaking memory
+ for (int i = 0; i < 100; i++)
+ {
+ for (int j = 0; j < 100; j++)
+ {
+ final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1.2." + i + "." + j);
+ final byte[] encoded1 = oid1.getEncoded();
+ final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1);
+ final ASN1ObjectIdentifier oid3 = ASN1ObjectIdentifier.getInstance(encoded1);
+ if (oid1 == oid2)
+ {
+ fail("Shouldn't be the same: " + oid1 + " " + oid2);
+ }
+ if (oid2 == oid3)
+ {
+ fail("Shouldn't be the same: " + oid2 + " " + oid3);
+ }
}
}
}
@@ -30,7 +77,7 @@ public class ObjectIdentifierTest
public static void main(
String[] args)
{
- ObjectIdentifierTest test = new ObjectIdentifierTest();
+ ObjectIdentifierTest test = new ObjectIdentifierTest();
TestResult result = test.perform();
System.out.println(result);
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java
index fb7763d1..1d618ffd 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java
@@ -5,6 +5,7 @@ import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
@@ -78,9 +79,9 @@ public class Accuracy
{
seconds = (ASN1Integer) seq.getObjectAt(i);
}
- else if (seq.getObjectAt(i) instanceof DERTaggedObject)
+ else if (seq.getObjectAt(i) instanceof ASN1TaggedObject)
{
- DERTaggedObject extra = (DERTaggedObject) seq.getObjectAt(i);
+ ASN1TaggedObject extra = (ASN1TaggedObject)seq.getObjectAt(i);
switch (extra.getTagNo())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java
index b551fcfb..2ba3c6bd 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java
@@ -8,6 +8,7 @@ import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.util.Arrays;
public class MessageImprint
extends ASN1Object
@@ -46,7 +47,7 @@ public class MessageImprint
byte[] hashedMessage)
{
this.hashAlgorithm = hashAlgorithm;
- this.hashedMessage = hashedMessage;
+ this.hashedMessage = Arrays.clone(hashedMessage);
}
public AlgorithmIdentifier getHashAlgorithm()
@@ -56,7 +57,7 @@ public class MessageImprint
public byte[] getHashedMessage()
{
- return hashedMessage;
+ return Arrays.clone(hashedMessage);
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
index 312224e5..eacb019d 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
@@ -72,7 +72,7 @@ public class TSTInfo
if (o instanceof ASN1TaggedObject)
{
- DERTaggedObject tagged = (DERTaggedObject) o;
+ ASN1TaggedObject tagged = (ASN1TaggedObject) o;
switch (tagged.getTagNo())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java b/bcprov/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java
index 3405130e..b9fac523 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java
@@ -149,6 +149,6 @@ public abstract class DSTU4145PointEncoder
throw new IllegalArgumentException("Invalid point compression");
}
- return curve.createPoint(xp.toBigInteger(), yp.toBigInteger());
+ return curve.validatePoint(xp.toBigInteger(), yp.toBigInteger());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
index 1330d256..59c961f2 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -38,6 +38,9 @@ import org.bouncycastle.asn1.DERVisibleString;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
+/**
+ * Utility class for dumping ASN.1 objects as (hopefully) human friendly strings.
+ */
public class ASN1Dump
{
private static final String TAB = " ";
@@ -319,7 +322,7 @@ public class ASN1Dump
return buf.toString();
}
- return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl;
+ return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + Strings.fromByteArray(Hex.encode(app.getContents())) + ")" + nl;
}
/**
@@ -376,7 +379,7 @@ public class ASN1Dump
if (bytes.length - i > SAMPLE_SIZE)
{
buf.append(indent);
- buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE)));
+ buf.append(Strings.fromByteArray(Hex.encode(bytes, i, SAMPLE_SIZE)));
buf.append(TAB);
buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
buf.append(nl);
@@ -384,7 +387,7 @@ public class ASN1Dump
else
{
buf.append(indent);
- buf.append(new String(Hex.encode(bytes, i, bytes.length - i)));
+ buf.append(Strings.fromByteArray(Hex.encode(bytes, i, bytes.length - i)));
for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
{
buf.append(" ");
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/util/Dump.java b/bcprov/src/main/java/org/bouncycastle/asn1/util/Dump.java
index 27a37f34..28d59e22 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/util/Dump.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/util/Dump.java
@@ -4,6 +4,12 @@ import java.io.FileInputStream;
import org.bouncycastle.asn1.ASN1InputStream;
+/**
+ * Command line ASN.1 Dump utility.
+ * <p>
+ * Usage: org.bouncycastle.asn1.util.Dump ber_encoded_file
+ * </p>
+ */
public class Dump
{
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
index 34b43856..2ef24d36 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -78,59 +78,50 @@ public class BCStyle
/**
* businessCategory - DirectoryString(SIZE(1..128)
*/
- public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
- "2.5.4.15").intern();
+ public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier("2.5.4.15").intern();
/**
* postalCode - DirectoryString(SIZE(1..40)
*/
- public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
- "2.5.4.17").intern();
+ public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier("2.5.4.17").intern();
/**
* dnQualifier - DirectoryString(SIZE(1..64)
*/
- public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
- "2.5.4.46").intern();
+ public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier("2.5.4.46").intern();
/**
* RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
*/
- public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
- "2.5.4.65").intern();
+ public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier("2.5.4.65").intern();
/**
* RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
*/
- public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
- "1.3.6.1.5.5.7.9.1").intern();
+ public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.1").intern();
/**
* RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
*/
- public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(
- "1.3.6.1.5.5.7.9.2").intern();
+ public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.2").intern();
/**
* RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
*/
- public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(
- "1.3.6.1.5.5.7.9.3").intern();
+ public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.3").intern();
/**
* RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
* codes only
*/
- public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(
- "1.3.6.1.5.5.7.9.4").intern();
+ public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.4").intern();
/**
* RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
* codes only
*/
- public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(
- "1.3.6.1.5.5.7.9.5").intern();
+ public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.5").intern();
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java
index acebcbe7..5cc85cdf 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java
@@ -125,6 +125,26 @@ public class DisplayText
private DisplayText(ASN1String de)
{
contents = de;
+ if (de instanceof DERUTF8String)
+ {
+ contentType = CONTENT_TYPE_UTF8STRING;
+ }
+ else if (de instanceof DERBMPString)
+ {
+ contentType = CONTENT_TYPE_BMPSTRING;
+ }
+ else if (de instanceof DERIA5String)
+ {
+ contentType = CONTENT_TYPE_IA5STRING;
+ }
+ else if (de instanceof DERVisibleString)
+ {
+ contentType = CONTENT_TYPE_VISIBLESTRING;
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown STRING type in DisplayText");
+ }
}
public static DisplayText getInstance(Object obj)
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
index 48e5640d..1a4c8dd2 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -66,6 +66,9 @@ public class DistributionPoint
break;
case 2:
cRLIssuer = GeneralNames.getInstance(t, false);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered in structure: " + t.getTagNo());
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java
index 456e3d32..b8c0473a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java
@@ -174,6 +174,11 @@ public class Extension
*/
public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55").intern();
+ /**
+ * Expired Certificates on CRL extension
+ */
+ public static final ASN1ObjectIdentifier expiredCertsOnCRL = new ASN1ObjectIdentifier("2.5.29.60").intern();
+
private ASN1ObjectIdentifier extnId;
private boolean critical;
private ASN1OctetString value;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
index 0a923a85..88cfe3a9 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
@@ -37,12 +37,14 @@ public class NameConstraints
ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement());
switch (o.getTagNo())
{
- case 0:
- permitted = createArray(ASN1Sequence.getInstance(o, false));
- break;
- case 1:
- excluded = createArray(ASN1Sequence.getInstance(o, false));
- break;
+ case 0:
+ permitted = createArray(ASN1Sequence.getInstance(o, false));
+ break;
+ case 1:
+ excluded = createArray(ASN1Sequence.getInstance(o, false));
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tag encountered: " + o.getTagNo());
}
}
}
@@ -62,15 +64,8 @@ public class NameConstraints
GeneralSubtree[] permitted,
GeneralSubtree[] excluded)
{
- if (permitted != null)
- {
- this.permitted = permitted;
- }
-
- if (excluded != null)
- {
- this.excluded = excluded;
- }
+ this.permitted = cloneSubtree(permitted);
+ this.excluded = cloneSubtree(excluded);
}
private GeneralSubtree[] createArray(ASN1Sequence subtree)
@@ -87,12 +82,12 @@ public class NameConstraints
public GeneralSubtree[] getPermittedSubtrees()
{
- return permitted;
+ return cloneSubtree(permitted);
}
public GeneralSubtree[] getExcludedSubtrees()
{
- return excluded;
+ return cloneSubtree(excluded);
}
/*
@@ -115,4 +110,18 @@ public class NameConstraints
return new DERSequence(v);
}
+
+ private static GeneralSubtree[] cloneSubtree(GeneralSubtree[] subtrees)
+ {
+ if (subtrees != null)
+ {
+ GeneralSubtree[] rv = new GeneralSubtree[subtrees.length];
+
+ System.arraycopy(subtrees, 0, rv, 0, rv.length);
+
+ return rv;
+ }
+
+ return null;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
index 5f0cd079..52e35a15 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
@@ -5,6 +5,7 @@ import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.util.Arrays;
/**
* The SubjectKeyIdentifier object.
@@ -47,22 +48,22 @@ public class SubjectKeyIdentifier
public SubjectKeyIdentifier(
byte[] keyid)
{
- this.keyidentifier = keyid;
+ this.keyidentifier = Arrays.clone(keyid);
}
protected SubjectKeyIdentifier(
ASN1OctetString keyid)
{
- this.keyidentifier = keyid.getOctets();
+ this(keyid.getOctets());
}
public byte[] getKeyIdentifier()
{
- return keyidentifier;
+ return Arrays.clone(keyidentifier);
}
public ASN1Primitive toASN1Primitive()
{
- return new DEROctetString(keyidentifier);
+ return new DEROctetString(getKeyIdentifier());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
index 23f99d0a..c7682f1a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -199,13 +199,13 @@ public class TBSCertList
}
if (seqPos < seq.size()
- && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))
+ && !(seq.getObjectAt(seqPos) instanceof ASN1TaggedObject))
{
revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
}
if (seqPos < seq.size()
- && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
+ && seq.getObjectAt(seqPos) instanceof ASN1TaggedObject)
{
crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
index dc419649..f7f60050 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
@@ -77,7 +77,7 @@ public class TBSCertificate
//
// some certficates don't include a version number - we assume v1
//
- if (seq.getObjectAt(0) instanceof DERTaggedObject)
+ if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
{
version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
}
@@ -109,7 +109,7 @@ public class TBSCertificate
for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
{
- DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+ ASN1TaggedObject extra = (ASN1TaggedObject)seq.getObjectAt(seqStart + 6 + extras);
switch (extra.getTagNo())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java
index ebc04051..029a66ae 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java
@@ -23,8 +23,8 @@ import org.bouncycastle.asn1.DERSequence;
public class UserNotice
extends ASN1Object
{
- private NoticeReference noticeRef;
- private DisplayText explicitText;
+ private final NoticeReference noticeRef;
+ private final DisplayText explicitText;
/**
* Creates a new <code>UserNotice</code> instance.
@@ -75,12 +75,19 @@ public class UserNotice
if (as.getObjectAt(0).toASN1Primitive() instanceof ASN1Sequence)
{
noticeRef = NoticeReference.getInstance(as.getObjectAt(0));
+ explicitText = null;
}
else
{
+ noticeRef = null;
explicitText = DisplayText.getInstance(as.getObjectAt(0));
}
}
+ else if (as.size() == 0) // neither field set!
+ {
+ noticeRef = null;
+ explicitText = null;
+ }
else
{
throw new IllegalArgumentException("Bad sequence size: " + as.size());
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java
index 22db8cb8..a95ac94d 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java
@@ -8,4 +8,11 @@ public interface ETSIQCObjectIdentifiers
static final ASN1ObjectIdentifier id_etsi_qcs_LimiteValue = new ASN1ObjectIdentifier("0.4.0.1862.1.2");
static final ASN1ObjectIdentifier id_etsi_qcs_RetentionPeriod = new ASN1ObjectIdentifier("0.4.0.1862.1.3");
static final ASN1ObjectIdentifier id_etsi_qcs_QcSSCD = new ASN1ObjectIdentifier("0.4.0.1862.1.4");
+
+ static final ASN1ObjectIdentifier id_etsi_qcs_QcPds = new ASN1ObjectIdentifier("0.4.0.1862.1.5");
+
+ static final ASN1ObjectIdentifier id_etsi_qcs_QcType = new ASN1ObjectIdentifier("0.4.0.1862.1.6");
+ static final ASN1ObjectIdentifier id_etsi_qct_esign = id_etsi_qcs_QcType.branch("1");
+ static final ASN1ObjectIdentifier id_etsi_qct_eseal = id_etsi_qcs_QcType.branch("2");
+ static final ASN1ObjectIdentifier id_etsi_qct_web = id_etsi_qcs_QcType.branch("3");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java
index 43d8d585..17cb9f13 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java
@@ -83,7 +83,7 @@ public class SemanticsInformation
GeneralName[] generalNames)
{
this.semanticsIdentifier = semanticsIdentifier;
- this.nameRegistrationAuthorities = generalNames;
+ this.nameRegistrationAuthorities = cloneNames(generalNames);
}
public SemanticsInformation(ASN1ObjectIdentifier semanticsIdentifier)
@@ -95,7 +95,7 @@ public class SemanticsInformation
public SemanticsInformation(GeneralName[] generalNames)
{
this.semanticsIdentifier = null;
- this.nameRegistrationAuthorities = generalNames;
+ this.nameRegistrationAuthorities = cloneNames(generalNames);
}
public ASN1ObjectIdentifier getSemanticsIdentifier()
@@ -105,7 +105,7 @@ public class SemanticsInformation
public GeneralName[] getNameRegistrationAuthorities()
{
- return nameRegistrationAuthorities;
+ return cloneNames(nameRegistrationAuthorities);
}
public ASN1Primitive toASN1Primitive()
@@ -127,5 +127,18 @@ public class SemanticsInformation
}
return new DERSequence(seq);
- }
+ }
+
+ private static GeneralName[] cloneNames(GeneralName[] names)
+ {
+ if (names != null)
+ {
+ GeneralName[] tmp = new GeneralName[names.length];
+
+ System.arraycopy(names, 0, tmp, 0, names.length);
+
+ return tmp;
+ }
+ return null;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java
index 1f65a332..fc4c201e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java
@@ -7,6 +7,7 @@ import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
@@ -67,7 +68,7 @@ public class OtherInfo
while (e.hasMoreElements())
{
- DERTaggedObject o = (DERTaggedObject)e.nextElement();
+ ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement();
if (o.getTagNo() == 0)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java
index 34ad746a..855974d2 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java
@@ -12,10 +12,13 @@ import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
/**
+ * Diffie-Hellman domain validation parameters.
+ * <pre>
* ValidationParams ::= SEQUENCE {
* seed BIT STRING,
* pgenCounter INTEGER
* }
+ * </pre>
*/
public class ValidationParams
extends ASN1Object
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
index 84574a3a..022c0183 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
@@ -11,7 +11,7 @@ import org.bouncycastle.util.encoders.Hex;
/**
- * table of the current named curves defined in X.962 EC-DSA.
+ * Table of the current named curves defined in X.962 EC-DSA.
*/
public class X962NamedCurves
{
@@ -546,7 +546,7 @@ public class X962NamedCurves
static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
{
- objIds.put(name.toLowerCase(), oid);
+ objIds.put(name, oid);
names.put(oid, name);
curves.put(oid, holder);
}
@@ -581,8 +581,14 @@ public class X962NamedCurves
public static X9ECParameters getByName(
String name)
{
- ASN1ObjectIdentifier oid = getOID(name);
- return oid == null ? null : getByOID(oid);
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
}
/**
@@ -595,7 +601,13 @@ public class X962NamedCurves
ASN1ObjectIdentifier oid)
{
X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
- return holder == null ? null : holder.getParameters();
+
+ if (holder != null)
+ {
+ return holder.getParameters();
+ }
+
+ return null;
}
/**
@@ -625,6 +637,6 @@ public class X962NamedCurves
*/
public static Enumeration getNames()
{
- return names.elements();
+ return objIds.keys();
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
index a06aa85f..2f26c66d 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
@@ -37,7 +37,7 @@ public class X962Parameters
{
return new X962Parameters(ASN1Primitive.fromByteArray((byte[])obj));
}
- catch (IOException e)
+ catch (Exception e)
{
throw new IllegalArgumentException("unable to parse encoded data: " + e.getMessage());
}
@@ -107,6 +107,6 @@ public class X962Parameters
*/
public ASN1Primitive toASN1Primitive()
{
- return (ASN1Primitive)params;
+ return params;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
index 57b0fda4..95fdc672 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -53,7 +53,7 @@ public class X9ECPoint
return Arrays.clone(encoding.getOctets());
}
- public ECPoint getPoint()
+ public synchronized ECPoint getPoint()
{
if (p == null)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
index 16a803cc..2851bcae 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
@@ -5,20 +5,43 @@ import java.math.BigInteger;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
+/**
+ * A class which converts integers to byte arrays, allowing padding and calculations
+ * to be done according the the filed size of the curve or field element involved.
+ */
public class X9IntegerConverter
{
+ /**
+ * Return the curve's field size in bytes.
+ *
+ * @param c the curve of interest.
+ * @return the field size in bytes (rounded up).
+ */
public int getByteLength(
ECCurve c)
{
return (c.getFieldSize() + 7) / 8;
}
+ /**
+ * Return the field element's field size in bytes.
+ *
+ * @param fe the field element of interest.
+ * @return the field size in bytes (rounded up).
+ */
public int getByteLength(
ECFieldElement fe)
{
return (fe.getFieldSize() + 7) / 8;
}
+ /**
+ * Convert an integer to a byte array, ensuring it is exactly qLength long.
+ *
+ * @param s the integer to be converted.
+ * @param qLength the length
+ * @return the resulting byte array.
+ */
public byte[] integerToBytes(
BigInteger s,
int qLength)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/Xof.java b/bcprov/src/main/java/org/bouncycastle/crypto/Xof.java
index 9183a7a2..fe85206b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/Xof.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/Xof.java
@@ -16,4 +16,15 @@ public interface Xof
* @return the number of bytes written
*/
int doFinal(byte[] out, int outOff, int outLen);
+
+ /**
+ * Start outputting the results of the final calculation for this digest. Unlike doFinal, this method
+ * will continue producing output until the Xof is explicitly reset, or signals otherwise.
+ *
+ * @param out output array to write the output bytes to.
+ * @param outOff offset to start writing the bytes at.
+ * @param outLen the number of output bytes requested.
+ * @return the number of bytes written
+ */
+ int doOutput(byte[] out, int outOff, int outLen);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
index 021a7153..84c5839e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
@@ -6,11 +6,11 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.generators.DHKeyPairGenerator;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
import org.bouncycastle.crypto.params.DHParameters;
-import org.bouncycastle.crypto.params.DHPublicKeyParameters;
import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
/**
@@ -26,6 +26,8 @@ import org.bouncycastle.crypto.params.ParametersWithRandom;
*/
public class DHAgreement
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
private DHPrivateKeyParameters key;
private DHParameters dhParams;
private BigInteger privateValue;
@@ -89,6 +91,12 @@ public class DHAgreement
BigInteger p = dhParams.getP();
- return message.modPow(key.getX(), p).multiply(pub.getY().modPow(privateValue, p)).mod(p);
+ BigInteger result = pub.getY().modPow(privateValue, p);
+ if (result.compareTo(ONE) == 0)
+ {
+ throw new IllegalStateException("Shared key can't be 1");
+ }
+
+ return message.modPow(key.getX(), p).multiply(result).mod(p);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
index d2e2a09f..4dd80d0a 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
@@ -20,6 +20,8 @@ import org.bouncycastle.crypto.params.ParametersWithRandom;
public class DHBasicAgreement
implements BasicAgreement
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
private DHPrivateKeyParameters key;
private DHParameters dhParams;
@@ -66,6 +68,12 @@ public class DHBasicAgreement
throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
}
- return pub.getY().modPow(key.getX(), dhParams.getP());
+ BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP());
+ if (result.compareTo(ONE) == 0)
+ {
+ throw new IllegalStateException("Shared key can't be 1");
+ }
+
+ return result;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java
index da4951d1..c34912af 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHStandardGroups.java
@@ -162,6 +162,10 @@ public class DHStandardGroups
+ "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
+ "855E6EEB22B3B2E5";
private static final String rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353";
+
+ /**
+ * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf
+ */
public static final DHParameters rfc5114_1024_160 = fromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g,
rfc5114_1024_160_q);
@@ -178,6 +182,10 @@ public class DHStandardGroups
+ "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
+ "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA";
private static final String rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB";
+
+ /**
+ * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf
+ */
public static final DHParameters rfc5114_2048_224 = fromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g,
rfc5114_2048_224_q);
@@ -195,6 +203,10 @@ public class DHStandardGroups
+ "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659";
private static final String rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B"
+ "A308B0FE64F5FBD3";
+
+ /**
+ * @deprecated Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf
+ */
public static final DHParameters rfc5114_2048_256 = fromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g,
rfc5114_2048_256_q);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
index a491b9df..8e2d1202 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
@@ -42,6 +42,11 @@ public class ECDHBasicAgreement
CipherParameters pubKey)
{
ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+ if (!pub.getParameters().equals(key.getParameters()))
+ {
+ throw new IllegalStateException("ECDH public key has wrong domain parameters");
+ }
+
ECPoint P = pub.getQ().multiply(key.getD()).normalize();
if (P.isInfinity())
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java
index 28140df7..3329cfb6 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java
@@ -49,6 +49,10 @@ public class ECDHCBasicAgreement
{
ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
ECDomainParameters params = pub.getParameters();
+ if (!params.equals(key.getParameters()))
+ {
+ throw new IllegalStateException("ECDHC public key has wrong domain parameters");
+ }
BigInteger hd = params.getH().multiply(key.getD()).mod(params.getN());
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java
index eb606bf3..a45ccd9b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java
@@ -41,8 +41,14 @@ public class ECMQVBasicAgreement
MQVPublicParameters pubParams = (MQVPublicParameters)pubKey;
ECPrivateKeyParameters staticPrivateKey = privParams.getStaticPrivateKey();
+ ECDomainParameters parameters = staticPrivateKey.getParameters();
- ECPoint agreement = calculateMqvAgreement(staticPrivateKey.getParameters(), staticPrivateKey,
+ if (!parameters.equals(pubParams.getStaticPublicKey().getParameters()))
+ {
+ throw new IllegalStateException("ECMQV public key components have wrong domain parameters");
+ }
+
+ ECPoint agreement = calculateMqvAgreement(parameters, staticPrivateKey,
privParams.getEphemeralPrivateKey(), privParams.getEphemeralPublicKey(),
pubParams.getStaticPublicKey(), pubParams.getEphemeralPublicKey()).normalize();
@@ -70,8 +76,8 @@ public class ECMQVBasicAgreement
ECCurve curve = parameters.getCurve();
ECPoint[] points = new ECPoint[]{
- // The Q2U public key is optional
- ECAlgorithms.importPoint(curve, Q2U == null ? parameters.getG().multiply(d2U.getD()) : Q2U.getQ()),
+ // The Q2U public key is optional - but will be calculated for us if it wasn't present
+ ECAlgorithms.importPoint(curve, Q2U.getQ()),
ECAlgorithms.importPoint(curve, Q1V.getQ()),
ECAlgorithms.importPoint(curve, Q2V.getQ())
};
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/kdf/ConcatenationKDFGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/kdf/ConcatenationKDFGenerator.java
index c3353f9d..3ec3cb60 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/kdf/ConcatenationKDFGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/kdf/ConcatenationKDFGenerator.java
@@ -39,7 +39,7 @@ public class ConcatenationKDFGenerator
}
else
{
- throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ throw new IllegalArgumentException("KDF parameters required for generator");
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java
index 0fd3ebb9..04af0ae8 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java
@@ -122,19 +122,28 @@ public class Blake2bDigest
this.key = Arrays.clone(digest.key);
this.digestLength = digest.digestLength;
this.chainValue = Arrays.clone(digest.chainValue);
- this.personalization = Arrays.clone(personalization);
+ this.personalization = Arrays.clone(digest.personalization);
+ this.salt = Arrays.clone(digest.salt);
+ this.t0 = digest.t0;
+ this.t1 = digest.t1;
+ this.f0 = digest.f0;
}
- public Blake2bDigest(int digestLength)
+ /**
+ * Basic sized constructor - size in bits.
+ *
+ * @param digestSize size of the digest in bits
+ */
+ public Blake2bDigest(int digestSize)
{
- if (digestLength != 160 && digestLength != 256 && digestLength != 384 && digestLength != 512)
+ if (digestSize != 160 && digestSize != 256 && digestSize != 384 && digestSize != 512)
{
throw new IllegalArgumentException("Blake2b digest restricted to one of [160, 256, 384, 512]");
}
buffer = new byte[BLOCK_LENGTH_BYTES];
keyLength = 0;
- this.digestLength = digestLength / 8;
+ this.digestLength = digestSize / 8;
init();
}
@@ -169,7 +178,7 @@ public class Blake2bDigest
}
/**
- * Blake2b with key, required digest length, salt and personalization.
+ * Blake2b with key, required digest length (in bytes), salt and personalization.
* After calling the doFinal() method, the key, the salt and the personal string
* will remain and might be used for further computations with this instance.
* The key can be overwritten using the clearKey() method, the salt (pepper)
@@ -177,11 +186,10 @@ public class Blake2bDigest
*
* @param key A key up to 64 bytes or null
* @param digestLength from 1 up to 64 bytes
- * @param salt up to 16 bytes or null
- * @param personalization up to 16 bytes or null
+ * @param salt 16 bytes or null
+ * @param personalization 16 bytes or null
*/
- public Blake2bDigest(byte[] key, int digestLength, byte[] salt,
- byte[] personalization)
+ public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization)
{
buffer = new byte[BLOCK_LENGTH_BYTES];
@@ -426,6 +434,7 @@ public class Blake2bDigest
chainValue = null;
if (key != null)
{
+ Arrays.fill(buffer, (byte) 0);
System.arraycopy(key, 0, buffer, 0, key.length);
bufferPos = BLOCK_LENGTH_BYTES; // zero padding
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012Digest.java
new file mode 100644
index 00000000..6efcb891
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012Digest.java
@@ -0,0 +1,1050 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Memoable;
+
+/**
+ * General Information
+ * <p/>
+ * 1. GOST R 34.11-2012 was developed by the Center for Information
+ * Protection and Special Communications of the Federal Security
+ * Service of the Russian Federation with participation of the Open
+ * joint-stock company "Information Technologies and Communication
+ * Systems" (InfoTeCS JSC).
+ * <p/>
+ * 2. GOST R 34.11-2012 was approved and introduced by Decree #216 of
+ * the Federal Agency on Technical Regulating and Metrology on
+ * 07.08.2012.
+ * <p/>
+ * 3. GOST R 34.11-2012 intended to replace GOST R 34.11-94 national
+ * standard of Russian Federation.
+ * <p/>
+ * Reference Implementation and Description can be found at: https://www.streebog.net/
+ * RFC: https://tools.ietf.org/html/rfc6986
+ */
+
+/**
+ * Base class for GOST3411-2012 256-bit and GOST3411-2012 512-bit digests.
+ */
+public abstract class GOST3411_2012Digest
+ implements ExtendedDigest, Memoable
+{
+ private final byte[] IV = new byte[64];
+ private final byte[] N = new byte[64];
+ private final byte[] Sigma = new byte[64];
+ private final byte[] Ki = new byte[64];
+ private final byte[] m = new byte[64];
+ private final byte[] h = new byte[64];
+
+ // Temporary buffers
+ private final byte[] tmp = new byte[64];
+ private final byte[] block = new byte[64];
+
+ private int bOff = 64;
+
+ public GOST3411_2012Digest(byte[] IV)
+ {
+ System.arraycopy(IV, 0, this.IV, 0, 64);
+ System.arraycopy(IV, 0, h, 0, 64);
+ }
+
+ public int getByteLength()
+ {
+ return 64;
+ }
+
+ public abstract String getAlgorithmName();
+
+ public abstract int getDigestSize();
+
+ public void update(byte in)
+ {
+ block[--bOff] = in;
+ if (bOff == 0)
+ {
+ g_N(h, N, block);
+ addMod512(N, 512);
+ addMod512(Sigma, block);
+ bOff = 64;
+ }
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ while (bOff != 64 && len > 0)
+ {
+ update(in[inOff++]);
+ len--;
+ }
+ while (len >= 64)
+ {
+ System.arraycopy(in, inOff, tmp, 0, 64);
+ reverse(tmp, block);
+ g_N(h, N, block);
+ addMod512(N, 512);
+ addMod512(Sigma, block);
+
+ len -= 64;
+ inOff += 64;
+ }
+ while (len > 0)
+ {
+ update(in[inOff++]);
+ len--;
+ }
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ int lenM = 64 - bOff;
+
+ // At this point it is certain that lenM is smaller than 64
+ for (int i = 0; i != 64 - lenM; i++)
+ {
+ m[i] = 0;
+ }
+
+ m[63 - lenM] = 1;
+
+ if (bOff != 64)
+ {
+ System.arraycopy(block, bOff, m, 64 - lenM, lenM);
+ }
+
+ g_N(h, N, m);
+ addMod512(N, lenM * 8);
+ addMod512(Sigma, m);
+ g_N(h, Zero, N);
+ g_N(h, Zero, Sigma);
+
+ reverse(h, tmp);
+ System.arraycopy(tmp, 0, out, outOff, 64);
+
+ reset();
+ return 64;
+ }
+
+ public void reset()
+ {
+ bOff = 64;
+ Arrays.fill(N, (byte)0);
+ Arrays.fill(Sigma, (byte)0);
+ System.arraycopy(IV, 0, h, 0, 64);
+ Arrays.fill(block, (byte)0);
+ }
+
+ public abstract Memoable copy();
+
+ public void reset(Memoable other)
+ {
+ GOST3411_2012Digest o = (GOST3411_2012Digest)other;
+
+ System.arraycopy(o.IV, 0, this.IV, 0, 64);
+ System.arraycopy(o.N, 0, this.N, 0, 64);
+ System.arraycopy(o.Sigma, 0, this.Sigma, 0, 64);
+ System.arraycopy(o.Ki, 0, this.Ki, 0, 64);
+ System.arraycopy(o.m, 0, this.m, 0, 64);
+ System.arraycopy(o.h, 0, this.h, 0, 64);
+
+ System.arraycopy(o.block, 0, this.block, 0, 64);
+ this.bOff = o.bOff;
+ }
+
+ private void F(byte[] V)
+ {
+ long[] res = new long[8];
+ long r;
+
+ r = 0;
+ r ^= T[0][(V[56] & 0xFF)];
+ r ^= T[1][(V[48] & 0xFF)];
+ r ^= T[2][(V[40] & 0xFF)];
+ r ^= T[3][(V[32] & 0xFF)];
+ r ^= T[4][(V[24] & 0xFF)];
+ r ^= T[5][(V[16] & 0xFF)];
+ r ^= T[6][(V[8] & 0xFF)];
+ r ^= T[7][(V[0] & 0xFF)];
+ res[0] = r;
+
+ r = 0;
+ r ^= T[0][(V[57] & 0xFF)];
+ r ^= T[1][(V[49] & 0xFF)];
+ r ^= T[2][(V[41] & 0xFF)];
+ r ^= T[3][(V[33] & 0xFF)];
+ r ^= T[4][(V[25] & 0xFF)];
+ r ^= T[5][(V[17] & 0xFF)];
+ r ^= T[6][(V[9] & 0xFF)];
+ r ^= T[7][(V[1] & 0xFF)];
+ res[1] = r;
+
+ r = 0;
+ r ^= T[0][(V[58] & 0xFF)];
+ r ^= T[1][(V[50] & 0xFF)];
+ r ^= T[2][(V[42] & 0xFF)];
+ r ^= T[3][(V[34] & 0xFF)];
+ r ^= T[4][(V[26] & 0xFF)];
+ r ^= T[5][(V[18] & 0xFF)];
+ r ^= T[6][(V[10] & 0xFF)];
+ r ^= T[7][(V[2] & 0xFF)];
+ res[2] = r;
+
+ r = 0;
+ r ^= T[0][(V[59] & 0xFF)];
+ r ^= T[1][(V[51] & 0xFF)];
+ r ^= T[2][(V[43] & 0xFF)];
+ r ^= T[3][(V[35] & 0xFF)];
+ r ^= T[4][(V[27] & 0xFF)];
+ r ^= T[5][(V[19] & 0xFF)];
+ r ^= T[6][(V[11] & 0xFF)];
+ r ^= T[7][(V[3] & 0xFF)];
+ res[3] = r;
+
+ r = 0;
+ r ^= T[0][(V[60] & 0xFF)];
+ r ^= T[1][(V[52] & 0xFF)];
+ r ^= T[2][(V[44] & 0xFF)];
+ r ^= T[3][(V[36] & 0xFF)];
+ r ^= T[4][(V[28] & 0xFF)];
+ r ^= T[5][(V[20] & 0xFF)];
+ r ^= T[6][(V[12] & 0xFF)];
+ r ^= T[7][(V[4] & 0xFF)];
+ res[4] = r;
+
+ r = 0;
+ r ^= T[0][(V[61] & 0xFF)];
+ r ^= T[1][(V[53] & 0xFF)];
+ r ^= T[2][(V[45] & 0xFF)];
+ r ^= T[3][(V[37] & 0xFF)];
+ r ^= T[4][(V[29] & 0xFF)];
+ r ^= T[5][(V[21] & 0xFF)];
+ r ^= T[6][(V[13] & 0xFF)];
+ r ^= T[7][(V[5] & 0xFF)];
+ res[5] = r;
+
+ r = 0;
+ r ^= T[0][(V[62] & 0xFF)];
+ r ^= T[1][(V[54] & 0xFF)];
+ r ^= T[2][(V[46] & 0xFF)];
+ r ^= T[3][(V[38] & 0xFF)];
+ r ^= T[4][(V[30] & 0xFF)];
+ r ^= T[5][(V[22] & 0xFF)];
+ r ^= T[6][(V[14] & 0xFF)];
+ r ^= T[7][(V[6] & 0xFF)];
+ res[6] = r;
+
+ r = 0;
+ r ^= T[0][(V[63] & 0xFF)];
+ r ^= T[1][(V[55] & 0xFF)];
+ r ^= T[2][(V[47] & 0xFF)];
+ r ^= T[3][(V[39] & 0xFF)];
+ r ^= T[4][(V[31] & 0xFF)];
+ r ^= T[5][(V[23] & 0xFF)];
+ r ^= T[6][(V[15] & 0xFF)];
+ r ^= T[7][(V[7] & 0xFF)];
+ res[7] = r;
+
+ r = res[0];
+ V[7] = (byte)(r >> 56);
+ V[6] = (byte)(r >> 48);
+ V[5] = (byte)(r >> 40);
+ V[4] = (byte)(r >> 32);
+ V[3] = (byte)(r >> 24);
+ V[2] = (byte)(r >> 16);
+ V[1] = (byte)(r >> 8);
+ V[0] = (byte)(r);
+
+ r = res[1];
+ V[15] = (byte)(r >> 56);
+ V[14] = (byte)(r >> 48);
+ V[13] = (byte)(r >> 40);
+ V[12] = (byte)(r >> 32);
+ V[11] = (byte)(r >> 24);
+ V[10] = (byte)(r >> 16);
+ V[9] = (byte)(r >> 8);
+ V[8] = (byte)(r);
+
+ r = res[2];
+ V[23] = (byte)(r >> 56);
+ V[22] = (byte)(r >> 48);
+ V[21] = (byte)(r >> 40);
+ V[20] = (byte)(r >> 32);
+ V[19] = (byte)(r >> 24);
+ V[18] = (byte)(r >> 16);
+ V[17] = (byte)(r >> 8);
+ V[16] = (byte)(r);
+
+ r = res[3];
+ V[31] = (byte)(r >> 56);
+ V[30] = (byte)(r >> 48);
+ V[29] = (byte)(r >> 40);
+ V[28] = (byte)(r >> 32);
+ V[27] = (byte)(r >> 24);
+ V[26] = (byte)(r >> 16);
+ V[25] = (byte)(r >> 8);
+ V[24] = (byte)(r);
+
+ r = res[4];
+ V[39] = (byte)(r >> 56);
+ V[38] = (byte)(r >> 48);
+ V[37] = (byte)(r >> 40);
+ V[36] = (byte)(r >> 32);
+ V[35] = (byte)(r >> 24);
+ V[34] = (byte)(r >> 16);
+ V[33] = (byte)(r >> 8);
+ V[32] = (byte)(r);
+
+ r = res[5];
+ V[47] = (byte)(r >> 56);
+ V[46] = (byte)(r >> 48);
+ V[45] = (byte)(r >> 40);
+ V[44] = (byte)(r >> 32);
+ V[43] = (byte)(r >> 24);
+ V[42] = (byte)(r >> 16);
+ V[41] = (byte)(r >> 8);
+ V[40] = (byte)(r);
+
+ r = res[6];
+ V[55] = (byte)(r >> 56);
+ V[54] = (byte)(r >> 48);
+ V[53] = (byte)(r >> 40);
+ V[52] = (byte)(r >> 32);
+ V[51] = (byte)(r >> 24);
+ V[50] = (byte)(r >> 16);
+ V[49] = (byte)(r >> 8);
+ V[48] = (byte)(r);
+
+ r = res[7];
+ V[63] = (byte)(r >> 56);
+ V[62] = (byte)(r >> 48);
+ V[61] = (byte)(r >> 40);
+ V[60] = (byte)(r >> 32);
+ V[59] = (byte)(r >> 24);
+ V[58] = (byte)(r >> 16);
+ V[57] = (byte)(r >> 8);
+ V[56] = (byte)(r);
+ }
+
+ private void xor512(byte[] A, byte[] B)
+ {
+ for (int i = 0; i < 64; ++i)
+ {
+ A[i] ^= B[i];
+ }
+ }
+
+ private void E(byte[] K, byte[] m)
+ {
+ System.arraycopy(K, 0, Ki, 0, 64);
+ xor512(K, m);
+ F(K);
+ for (int i = 0; i < 11; ++i)
+ {
+ xor512(Ki, C[i]);
+ F(Ki);
+ xor512(K, Ki);
+ F(K);
+ }
+ xor512(Ki, C[11]);
+ F(Ki);
+ xor512(K, Ki);
+ }
+
+ private void g_N(byte[] h, byte[] N, byte[] m)
+ {
+ System.arraycopy(h, 0, tmp, 0, 64);
+
+ xor512(h, N);
+ F(h);
+
+ E(h, m);
+ xor512(h, tmp);
+ xor512(h, m);
+ }
+
+ private void addMod512(byte[] A, int num)
+ {
+ int c;
+ c = (A[63] & 0xFF) + (num & 0xFF);
+ A[63] = (byte)c;
+
+ c = (A[62] & 0xFF) + ((num >> 8) & 0xFF) + (c >> 8);
+ A[62] = (byte)c;
+
+ for (int i = 61; (i >= 0) && (c > 0); --i)
+ {
+ c = (A[i] & 0xFF) + (c >> 8);
+ A[i] = (byte)c;
+ }
+ }
+
+ private void addMod512(byte[] A, byte[] B)
+ {
+ for (int c = 0, i = 63; i >= 0; --i)
+ {
+ c = (A[i] & 0xFF) + (B[i] & 0xFF) + (c >> 8);
+ A[i] = (byte)c;
+ }
+ }
+
+ private void reverse(byte[] src, byte[] dst)
+ {
+ final int len = src.length;
+ for (int i = 0; i < len; i++)
+ {
+ dst[len - 1 - i] = src[i];
+ }
+ }
+
+ private final static byte[][] C = {{
+ (byte)0xb1, (byte)0x08, (byte)0x5b, (byte)0xda, (byte)0x1e, (byte)0xca, (byte)0xda, (byte)0xe9,
+ (byte)0xeb, (byte)0xcb, (byte)0x2f, (byte)0x81, (byte)0xc0, (byte)0x65, (byte)0x7c, (byte)0x1f,
+ (byte)0x2f, (byte)0x6a, (byte)0x76, (byte)0x43, (byte)0x2e, (byte)0x45, (byte)0xd0, (byte)0x16,
+ (byte)0x71, (byte)0x4e, (byte)0xb8, (byte)0x8d, (byte)0x75, (byte)0x85, (byte)0xc4, (byte)0xfc,
+ (byte)0x4b, (byte)0x7c, (byte)0xe0, (byte)0x91, (byte)0x92, (byte)0x67, (byte)0x69, (byte)0x01,
+ (byte)0xa2, (byte)0x42, (byte)0x2a, (byte)0x08, (byte)0xa4, (byte)0x60, (byte)0xd3, (byte)0x15,
+ (byte)0x05, (byte)0x76, (byte)0x74, (byte)0x36, (byte)0xcc, (byte)0x74, (byte)0x4d, (byte)0x23,
+ (byte)0xdd, (byte)0x80, (byte)0x65, (byte)0x59, (byte)0xf2, (byte)0xa6, (byte)0x45, (byte)0x07},
+ {
+ (byte)0x6f, (byte)0xa3, (byte)0xb5, (byte)0x8a, (byte)0xa9, (byte)0x9d, (byte)0x2f, (byte)0x1a,
+ (byte)0x4f, (byte)0xe3, (byte)0x9d, (byte)0x46, (byte)0x0f, (byte)0x70, (byte)0xb5, (byte)0xd7,
+ (byte)0xf3, (byte)0xfe, (byte)0xea, (byte)0x72, (byte)0x0a, (byte)0x23, (byte)0x2b, (byte)0x98,
+ (byte)0x61, (byte)0xd5, (byte)0x5e, (byte)0x0f, (byte)0x16, (byte)0xb5, (byte)0x01, (byte)0x31,
+ (byte)0x9a, (byte)0xb5, (byte)0x17, (byte)0x6b, (byte)0x12, (byte)0xd6, (byte)0x99, (byte)0x58,
+ (byte)0x5c, (byte)0xb5, (byte)0x61, (byte)0xc2, (byte)0xdb, (byte)0x0a, (byte)0xa7, (byte)0xca,
+ (byte)0x55, (byte)0xdd, (byte)0xa2, (byte)0x1b, (byte)0xd7, (byte)0xcb, (byte)0xcd, (byte)0x56,
+ (byte)0xe6, (byte)0x79, (byte)0x04, (byte)0x70, (byte)0x21, (byte)0xb1, (byte)0x9b, (byte)0xb7},
+ {
+ (byte)0xf5, (byte)0x74, (byte)0xdc, (byte)0xac, (byte)0x2b, (byte)0xce, (byte)0x2f, (byte)0xc7,
+ (byte)0x0a, (byte)0x39, (byte)0xfc, (byte)0x28, (byte)0x6a, (byte)0x3d, (byte)0x84, (byte)0x35,
+ (byte)0x06, (byte)0xf1, (byte)0x5e, (byte)0x5f, (byte)0x52, (byte)0x9c, (byte)0x1f, (byte)0x8b,
+ (byte)0xf2, (byte)0xea, (byte)0x75, (byte)0x14, (byte)0xb1, (byte)0x29, (byte)0x7b, (byte)0x7b,
+ (byte)0xd3, (byte)0xe2, (byte)0x0f, (byte)0xe4, (byte)0x90, (byte)0x35, (byte)0x9e, (byte)0xb1,
+ (byte)0xc1, (byte)0xc9, (byte)0x3a, (byte)0x37, (byte)0x60, (byte)0x62, (byte)0xdb, (byte)0x09,
+ (byte)0xc2, (byte)0xb6, (byte)0xf4, (byte)0x43, (byte)0x86, (byte)0x7a, (byte)0xdb, (byte)0x31,
+ (byte)0x99, (byte)0x1e, (byte)0x96, (byte)0xf5, (byte)0x0a, (byte)0xba, (byte)0x0a, (byte)0xb2},
+ {
+ (byte)0xef, (byte)0x1f, (byte)0xdf, (byte)0xb3, (byte)0xe8, (byte)0x15, (byte)0x66, (byte)0xd2,
+ (byte)0xf9, (byte)0x48, (byte)0xe1, (byte)0xa0, (byte)0x5d, (byte)0x71, (byte)0xe4, (byte)0xdd,
+ (byte)0x48, (byte)0x8e, (byte)0x85, (byte)0x7e, (byte)0x33, (byte)0x5c, (byte)0x3c, (byte)0x7d,
+ (byte)0x9d, (byte)0x72, (byte)0x1c, (byte)0xad, (byte)0x68, (byte)0x5e, (byte)0x35, (byte)0x3f,
+ (byte)0xa9, (byte)0xd7, (byte)0x2c, (byte)0x82, (byte)0xed, (byte)0x03, (byte)0xd6, (byte)0x75,
+ (byte)0xd8, (byte)0xb7, (byte)0x13, (byte)0x33, (byte)0x93, (byte)0x52, (byte)0x03, (byte)0xbe,
+ (byte)0x34, (byte)0x53, (byte)0xea, (byte)0xa1, (byte)0x93, (byte)0xe8, (byte)0x37, (byte)0xf1,
+ (byte)0x22, (byte)0x0c, (byte)0xbe, (byte)0xbc, (byte)0x84, (byte)0xe3, (byte)0xd1, (byte)0x2e},
+ {
+ (byte)0x4b, (byte)0xea, (byte)0x6b, (byte)0xac, (byte)0xad, (byte)0x47, (byte)0x47, (byte)0x99,
+ (byte)0x9a, (byte)0x3f, (byte)0x41, (byte)0x0c, (byte)0x6c, (byte)0xa9, (byte)0x23, (byte)0x63,
+ (byte)0x7f, (byte)0x15, (byte)0x1c, (byte)0x1f, (byte)0x16, (byte)0x86, (byte)0x10, (byte)0x4a,
+ (byte)0x35, (byte)0x9e, (byte)0x35, (byte)0xd7, (byte)0x80, (byte)0x0f, (byte)0xff, (byte)0xbd,
+ (byte)0xbf, (byte)0xcd, (byte)0x17, (byte)0x47, (byte)0x25, (byte)0x3a, (byte)0xf5, (byte)0xa3,
+ (byte)0xdf, (byte)0xff, (byte)0x00, (byte)0xb7, (byte)0x23, (byte)0x27, (byte)0x1a, (byte)0x16,
+ (byte)0x7a, (byte)0x56, (byte)0xa2, (byte)0x7e, (byte)0xa9, (byte)0xea, (byte)0x63, (byte)0xf5,
+ (byte)0x60, (byte)0x17, (byte)0x58, (byte)0xfd, (byte)0x7c, (byte)0x6c, (byte)0xfe, (byte)0x57},
+ {
+ (byte)0xae, (byte)0x4f, (byte)0xae, (byte)0xae, (byte)0x1d, (byte)0x3a, (byte)0xd3, (byte)0xd9,
+ (byte)0x6f, (byte)0xa4, (byte)0xc3, (byte)0x3b, (byte)0x7a, (byte)0x30, (byte)0x39, (byte)0xc0,
+ (byte)0x2d, (byte)0x66, (byte)0xc4, (byte)0xf9, (byte)0x51, (byte)0x42, (byte)0xa4, (byte)0x6c,
+ (byte)0x18, (byte)0x7f, (byte)0x9a, (byte)0xb4, (byte)0x9a, (byte)0xf0, (byte)0x8e, (byte)0xc6,
+ (byte)0xcf, (byte)0xfa, (byte)0xa6, (byte)0xb7, (byte)0x1c, (byte)0x9a, (byte)0xb7, (byte)0xb4,
+ (byte)0x0a, (byte)0xf2, (byte)0x1f, (byte)0x66, (byte)0xc2, (byte)0xbe, (byte)0xc6, (byte)0xb6,
+ (byte)0xbf, (byte)0x71, (byte)0xc5, (byte)0x72, (byte)0x36, (byte)0x90, (byte)0x4f, (byte)0x35,
+ (byte)0xfa, (byte)0x68, (byte)0x40, (byte)0x7a, (byte)0x46, (byte)0x64, (byte)0x7d, (byte)0x6e},
+ {
+ (byte)0xf4, (byte)0xc7, (byte)0x0e, (byte)0x16, (byte)0xee, (byte)0xaa, (byte)0xc5, (byte)0xec,
+ (byte)0x51, (byte)0xac, (byte)0x86, (byte)0xfe, (byte)0xbf, (byte)0x24, (byte)0x09, (byte)0x54,
+ (byte)0x39, (byte)0x9e, (byte)0xc6, (byte)0xc7, (byte)0xe6, (byte)0xbf, (byte)0x87, (byte)0xc9,
+ (byte)0xd3, (byte)0x47, (byte)0x3e, (byte)0x33, (byte)0x19, (byte)0x7a, (byte)0x93, (byte)0xc9,
+ (byte)0x09, (byte)0x92, (byte)0xab, (byte)0xc5, (byte)0x2d, (byte)0x82, (byte)0x2c, (byte)0x37,
+ (byte)0x06, (byte)0x47, (byte)0x69, (byte)0x83, (byte)0x28, (byte)0x4a, (byte)0x05, (byte)0x04,
+ (byte)0x35, (byte)0x17, (byte)0x45, (byte)0x4c, (byte)0xa2, (byte)0x3c, (byte)0x4a, (byte)0xf3,
+ (byte)0x88, (byte)0x86, (byte)0x56, (byte)0x4d, (byte)0x3a, (byte)0x14, (byte)0xd4, (byte)0x93},
+ {
+ (byte)0x9b, (byte)0x1f, (byte)0x5b, (byte)0x42, (byte)0x4d, (byte)0x93, (byte)0xc9, (byte)0xa7,
+ (byte)0x03, (byte)0xe7, (byte)0xaa, (byte)0x02, (byte)0x0c, (byte)0x6e, (byte)0x41, (byte)0x41,
+ (byte)0x4e, (byte)0xb7, (byte)0xf8, (byte)0x71, (byte)0x9c, (byte)0x36, (byte)0xde, (byte)0x1e,
+ (byte)0x89, (byte)0xb4, (byte)0x44, (byte)0x3b, (byte)0x4d, (byte)0xdb, (byte)0xc4, (byte)0x9a,
+ (byte)0xf4, (byte)0x89, (byte)0x2b, (byte)0xcb, (byte)0x92, (byte)0x9b, (byte)0x06, (byte)0x90,
+ (byte)0x69, (byte)0xd1, (byte)0x8d, (byte)0x2b, (byte)0xd1, (byte)0xa5, (byte)0xc4, (byte)0x2f,
+ (byte)0x36, (byte)0xac, (byte)0xc2, (byte)0x35, (byte)0x59, (byte)0x51, (byte)0xa8, (byte)0xd9,
+ (byte)0xa4, (byte)0x7f, (byte)0x0d, (byte)0xd4, (byte)0xbf, (byte)0x02, (byte)0xe7, (byte)0x1e},
+ {
+ (byte)0x37, (byte)0x8f, (byte)0x5a, (byte)0x54, (byte)0x16, (byte)0x31, (byte)0x22, (byte)0x9b,
+ (byte)0x94, (byte)0x4c, (byte)0x9a, (byte)0xd8, (byte)0xec, (byte)0x16, (byte)0x5f, (byte)0xde,
+ (byte)0x3a, (byte)0x7d, (byte)0x3a, (byte)0x1b, (byte)0x25, (byte)0x89, (byte)0x42, (byte)0x24,
+ (byte)0x3c, (byte)0xd9, (byte)0x55, (byte)0xb7, (byte)0xe0, (byte)0x0d, (byte)0x09, (byte)0x84,
+ (byte)0x80, (byte)0x0a, (byte)0x44, (byte)0x0b, (byte)0xdb, (byte)0xb2, (byte)0xce, (byte)0xb1,
+ (byte)0x7b, (byte)0x2b, (byte)0x8a, (byte)0x9a, (byte)0xa6, (byte)0x07, (byte)0x9c, (byte)0x54,
+ (byte)0x0e, (byte)0x38, (byte)0xdc, (byte)0x92, (byte)0xcb, (byte)0x1f, (byte)0x2a, (byte)0x60,
+ (byte)0x72, (byte)0x61, (byte)0x44, (byte)0x51, (byte)0x83, (byte)0x23, (byte)0x5a, (byte)0xdb},
+ {
+ (byte)0xab, (byte)0xbe, (byte)0xde, (byte)0xa6, (byte)0x80, (byte)0x05, (byte)0x6f, (byte)0x52,
+ (byte)0x38, (byte)0x2a, (byte)0xe5, (byte)0x48, (byte)0xb2, (byte)0xe4, (byte)0xf3, (byte)0xf3,
+ (byte)0x89, (byte)0x41, (byte)0xe7, (byte)0x1c, (byte)0xff, (byte)0x8a, (byte)0x78, (byte)0xdb,
+ (byte)0x1f, (byte)0xff, (byte)0xe1, (byte)0x8a, (byte)0x1b, (byte)0x33, (byte)0x61, (byte)0x03,
+ (byte)0x9f, (byte)0xe7, (byte)0x67, (byte)0x02, (byte)0xaf, (byte)0x69, (byte)0x33, (byte)0x4b,
+ (byte)0x7a, (byte)0x1e, (byte)0x6c, (byte)0x30, (byte)0x3b, (byte)0x76, (byte)0x52, (byte)0xf4,
+ (byte)0x36, (byte)0x98, (byte)0xfa, (byte)0xd1, (byte)0x15, (byte)0x3b, (byte)0xb6, (byte)0xc3,
+ (byte)0x74, (byte)0xb4, (byte)0xc7, (byte)0xfb, (byte)0x98, (byte)0x45, (byte)0x9c, (byte)0xed},
+ {
+ (byte)0x7b, (byte)0xcd, (byte)0x9e, (byte)0xd0, (byte)0xef, (byte)0xc8, (byte)0x89, (byte)0xfb,
+ (byte)0x30, (byte)0x02, (byte)0xc6, (byte)0xcd, (byte)0x63, (byte)0x5a, (byte)0xfe, (byte)0x94,
+ (byte)0xd8, (byte)0xfa, (byte)0x6b, (byte)0xbb, (byte)0xeb, (byte)0xab, (byte)0x07, (byte)0x61,
+ (byte)0x20, (byte)0x01, (byte)0x80, (byte)0x21, (byte)0x14, (byte)0x84, (byte)0x66, (byte)0x79,
+ (byte)0x8a, (byte)0x1d, (byte)0x71, (byte)0xef, (byte)0xea, (byte)0x48, (byte)0xb9, (byte)0xca,
+ (byte)0xef, (byte)0xba, (byte)0xcd, (byte)0x1d, (byte)0x7d, (byte)0x47, (byte)0x6e, (byte)0x98,
+ (byte)0xde, (byte)0xa2, (byte)0x59, (byte)0x4a, (byte)0xc0, (byte)0x6f, (byte)0xd8, (byte)0x5d,
+ (byte)0x6b, (byte)0xca, (byte)0xa4, (byte)0xcd, (byte)0x81, (byte)0xf3, (byte)0x2d, (byte)0x1b},
+ {
+ (byte)0x37, (byte)0x8e, (byte)0xe7, (byte)0x67, (byte)0xf1, (byte)0x16, (byte)0x31, (byte)0xba,
+ (byte)0xd2, (byte)0x13, (byte)0x80, (byte)0xb0, (byte)0x04, (byte)0x49, (byte)0xb1, (byte)0x7a,
+ (byte)0xcd, (byte)0xa4, (byte)0x3c, (byte)0x32, (byte)0xbc, (byte)0xdf, (byte)0x1d, (byte)0x77,
+ (byte)0xf8, (byte)0x20, (byte)0x12, (byte)0xd4, (byte)0x30, (byte)0x21, (byte)0x9f, (byte)0x9b,
+ (byte)0x5d, (byte)0x80, (byte)0xef, (byte)0x9d, (byte)0x18, (byte)0x91, (byte)0xcc, (byte)0x86,
+ (byte)0xe7, (byte)0x1d, (byte)0xa4, (byte)0xaa, (byte)0x88, (byte)0xe1, (byte)0x28, (byte)0x52,
+ (byte)0xfa, (byte)0xf4, (byte)0x17, (byte)0xd5, (byte)0xd9, (byte)0xb2, (byte)0x1b, (byte)0x99,
+ (byte)0x48, (byte)0xbc, (byte)0x92, (byte)0x4a, (byte)0xf1, (byte)0x1b, (byte)0xd7, (byte)0x20}
+ };
+
+ private final static byte[] Zero = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ private final static long[][] T = {
+ {
+ 0xE6F87E5C5B711FD0L, 0x258377800924FA16L, 0xC849E07E852EA4A8L, 0x5B4686A18F06C16AL,
+ 0x0B32E9A2D77B416EL, 0xABDA37A467815C66L, 0xF61796A81A686676L, 0xF5DC0B706391954BL,
+ 0x4862F38DB7E64BF1L, 0xFF5C629A68BD85C5L, 0xCB827DA6FCD75795L, 0x66D36DAF69B9F089L,
+ 0x356C9F74483D83B0L, 0x7CBCECB1238C99A1L, 0x36A702AC31C4708DL, 0x9EB6A8D02FBCDFD6L,
+ 0x8B19FA51E5B3AE37L, 0x9CCFB5408A127D0BL, 0xBC0C78B508208F5AL, 0xE533E3842288ECEDL,
+ 0xCEC2C7D377C15FD2L, 0xEC7817B6505D0F5EL, 0xB94CC2C08336871DL, 0x8C205DB4CB0B04ADL,
+ 0x763C855B28A0892FL, 0x588D1B79F6FF3257L, 0x3FECF69E4311933EL, 0x0FC0D39F803A18C9L,
+ 0xEE010A26F5F3AD83L, 0x10EFE8F4411979A6L, 0x5DCDA10C7DE93A10L, 0x4A1BEE1D1248E92CL,
+ 0x53BFF2DB21847339L, 0xB4F50CCFA6A23D09L, 0x5FB4BC9CD84798CDL, 0xE88A2D8B071C56F9L,
+ 0x7F7771695A756A9CL, 0xC5F02E71A0BA1EBCL, 0xA663F9AB4215E672L, 0x2EB19E22DE5FBB78L,
+ 0x0DB9CE0F2594BA14L, 0x82520E6397664D84L, 0x2F031E6A0208EA98L, 0x5C7F2144A1BE6BF0L,
+ 0x7A37CB1CD16362DBL, 0x83E08E2B4B311C64L, 0xCF70479BAB960E32L, 0x856BA986B9DEE71EL,
+ 0xB5478C877AF56CE9L, 0xB8FE42885F61D6FDL, 0x1BDD0156966238C8L, 0x622157923EF8A92EL,
+ 0xFC97FF42114476F8L, 0x9D7D350856452CEBL, 0x4C90C9B0E0A71256L, 0x2308502DFBCB016CL,
+ 0x2D7A03FAA7A64845L, 0xF46E8B38BFC6C4ABL, 0xBDBEF8FDD477DEBAL, 0x3AAC4CEBC8079B79L,
+ 0xF09CB105E8879D0CL, 0x27FA6A10AC8A58CBL, 0x8960E7C1401D0CEAL, 0x1A6F811E4A356928L,
+ 0x90C4FB0773D196FFL, 0x43501A2F609D0A9FL, 0xF7A516E0C63F3796L, 0x1CE4A6B3B8DA9252L,
+ 0x1324752C38E08A9BL, 0xA5A864733BEC154FL, 0x2BF124575549B33FL, 0xD766DB15440DC5C7L,
+ 0xA7D179E39E42B792L, 0xDADF151A61997FD3L, 0x86A0345EC0271423L, 0x38D5517B6DA939A4L,
+ 0x6518F077104003B4L, 0x02791D90A5AEA2DDL, 0x88D267899C4A5D0AL, 0x930F66DF0A2865C2L,
+ 0x4EE9D4204509B08BL, 0x325538916685292AL, 0x412907BFC533A842L, 0xB27E2B62544DC673L,
+ 0x6C5304456295E007L, 0x5AF406E95351908AL, 0x1F2F3B6BC123616FL, 0xC37B09DC5255E5C6L,
+ 0x3967D133B1FE6844L, 0x298839C7F0E711E2L, 0x409B87F71964F9A2L, 0xE938ADC3DB4B0719L,
+ 0x0C0B4E47F9C3EBF4L, 0x5534D576D36B8843L, 0x4610A05AEB8B02D8L, 0x20C3CDF58232F251L,
+ 0x6DE1840DBEC2B1E7L, 0xA0E8DE06B0FA1D08L, 0x7B854B540D34333BL, 0x42E29A67BCCA5B7FL,
+ 0xD8A6088AC437DD0EL, 0xC63BB3A9D943ED81L, 0x21714DBD5E65A3B1L, 0x6761EDE7B5EEA169L,
+ 0x2431F7C8D573ABF6L, 0xD51FC685E1A3671AL, 0x5E063CD40410C92DL, 0x283AB98F2CB04002L,
+ 0x8FEBC06CB2F2F790L, 0x17D64F116FA1D33CL, 0xE07359F1A99EE4AAL, 0x784ED68C74CDC006L,
+ 0x6E2A19D5C73B42DAL, 0x8712B4161C7045C3L, 0x371582E4ED93216DL, 0xACE390414939F6FCL,
+ 0x7EC5F12186223B7CL, 0xC0B094042BAC16FBL, 0xF9D745379A527EBFL, 0x737C3F2EA3B68168L,
+ 0x33E7B8D9BAD278CAL, 0xA9A32A34C22FFEBBL, 0xE48163CCFEDFBD0DL, 0x8E5940246EA5A670L,
+ 0x51C6EF4B842AD1E4L, 0x22BAD065279C508CL, 0xD91488C218608CEEL, 0x319EA5491F7CDA17L,
+ 0xD394E128134C9C60L, 0x094BF43272D5E3B3L, 0x9BF612A5A4AAD791L, 0xCCBBDA43D26FFD0FL,
+ 0x34DE1F3C946AD250L, 0x4F5B5468995EE16BL, 0xDF9FAF6FEA8F7794L, 0x2648EA5870DD092BL,
+ 0xBFC7E56D71D97C67L, 0xDDE6B2FF4F21D549L, 0x3C276B463AE86003L, 0x91767B4FAF86C71FL,
+ 0x68A13E7835D4B9A0L, 0xB68C115F030C9FD4L, 0x141DD2C916582001L, 0x983D8F7DDD5324ACL,
+ 0x64AA703FCC175254L, 0xC2C989948E02B426L, 0x3E5E76D69F46C2DEL, 0x50746F03587D8004L,
+ 0x45DB3D829272F1E5L, 0x60584A029B560BF3L, 0xFBAE58A73FFCDC62L, 0xA15A5E4E6CAD4CE8L,
+ 0x4BA96E55CE1FB8CCL, 0x08F9747AAE82B253L, 0xC102144CF7FB471BL, 0x9F042898F3EB8E36L,
+ 0x068B27ADF2EFFB7AL, 0xEDCA97FE8C0A5EBEL, 0x778E0513F4F7D8CFL, 0x302C2501C32B8BF7L,
+ 0x8D92DDFC175C554DL, 0xF865C57F46052F5FL, 0xEAF3301BA2B2F424L, 0xAA68B7ECBBD60D86L,
+ 0x998F0F350104754CL, 0x0000000000000000L, 0xF12E314D34D0CCECL, 0x710522BE061823B5L,
+ 0xAF280D9930C005C1L, 0x97FD5CE25D693C65L, 0x19A41CC633CC9A15L, 0x95844172F8C79EB8L,
+ 0xDC5432B7937684A9L, 0x9436C13A2490CF58L, 0x802B13F332C8EF59L, 0xC442AE397CED4F5CL,
+ 0xFA1CD8EFE3AB8D82L, 0xF2E5AC954D293FD1L, 0x6AD823E8907A1B7DL, 0x4D2249F83CF043B6L,
+ 0x03CB9DD879F9F33DL, 0xDE2D2F2736D82674L, 0x2A43A41F891EE2DFL, 0x6F98999D1B6C133AL,
+ 0xD4AD46CD3DF436FAL, 0xBB35DF50269825C0L, 0x964FDCAA813E6D85L, 0xEB41B0537EE5A5C4L,
+ 0x0540BA758B160847L, 0xA41AE43BE7BB44AFL, 0xE3B8C429D0671797L, 0x819993BBEE9FBEB9L,
+ 0xAE9A8DD1EC975421L, 0xF3572CDD917E6E31L, 0x6393D7DAE2AFF8CEL, 0x47A2201237DC5338L,
+ 0xA32343DEC903EE35L, 0x79FC56C4A89A91E6L, 0x01B28048DC5751E0L, 0x1296F564E4B7DB7BL,
+ 0x75F7188351597A12L, 0xDB6D9552BDCE2E33L, 0x1E9DBB231D74308FL, 0x520D7293FDD322D9L,
+ 0xE20A44610C304677L, 0xFEEEE2D2B4EAD425L, 0xCA30FDEE20800675L, 0x61EACA4A47015A13L,
+ 0xE74AFE1487264E30L, 0x2CC883B27BF119A5L, 0x1664CF59B3F682DCL, 0xA811AA7C1E78AF5BL,
+ 0x1D5626FB648DC3B2L, 0xB73E9117DF5BCE34L, 0xD05F7CF06AB56F5DL, 0xFD257F0ACD132718L,
+ 0x574DC8E676C52A9EL, 0x0739A7E52EB8AA9AL, 0x5486553E0F3CD9A3L, 0x56FF48AEAA927B7EL,
+ 0xBE756525AD8E2D87L, 0x7D0E6CF9FFDBC841L, 0x3B1ECCA31450CA99L, 0x6913BE30E983E840L,
+ 0xAD511009956EA71CL, 0xB1B5B6BA2DB4354EL, 0x4469BDCA4E25A005L, 0x15AF5281CA0F71E1L,
+ 0x744598CB8D0E2BF2L, 0x593F9B312AA863B7L, 0xEFB38A6E29A4FC63L, 0x6B6AA3A04C2D4A9DL,
+ 0x3D95EB0EE6BF31E3L, 0xA291C3961554BFD5L, 0x18169C8EEF9BCBF5L, 0x115D68BC9D4E2846L,
+ 0xBA875F18FACF7420L, 0xD1EDFCB8B6E23EBDL, 0xB00736F2F1E364AEL, 0x84D929CE6589B6FEL,
+ 0x70B7A2F6DA4F7255L, 0x0E7253D75C6D4929L, 0x04F23A3D574159A7L, 0x0A8069EA0B2C108EL,
+ 0x49D073C56BB11A11L, 0x8AAB7A1939E4FFD7L, 0xCD095A0B0E38ACEFL, 0xC9FB60365979F548L,
+ 0x92BDE697D67F3422L, 0xC78933E10514BC61L, 0xE1C1D9B975C9B54AL, 0xD2266160CF1BCD80L,
+ 0x9A4492ED78FD8671L, 0xB3CCAB2A881A9793L, 0x72CEBF667FE1D088L, 0xD6D45B5D985A9427L
+ },
+ {
+ 0xC811A8058C3F55DEL, 0x65F5B43196B50619L, 0xF74F96B1D6706E43L, 0x859D1E8BCB43D336L,
+ 0x5AAB8A85CCFA3D84L, 0xF9C7BF99C295FCFDL, 0xA21FD5A1DE4B630FL, 0xCDB3EF763B8B456DL,
+ 0x803F59F87CF7C385L, 0xB27C73BE5F31913CL, 0x98E3AC6633B04821L, 0xBF61674C26B8F818L,
+ 0x0FFBC995C4C130C8L, 0xAAA0862010761A98L, 0x6057F342210116AAL, 0xF63C760C0654CC35L,
+ 0x2DDB45CC667D9042L, 0xBCF45A964BD40382L, 0x68E8A0C3EF3C6F3DL, 0xA7BD92D269FF73BCL,
+ 0x290AE20201ED2287L, 0xB7DE34CDE885818FL, 0xD901EEA7DD61059BL, 0xD6FA273219A03553L,
+ 0xD56F1AE874CCCEC9L, 0xEA31245C2E83F554L, 0x7034555DA07BE499L, 0xCE26D2AC56E7BEF7L,
+ 0xFD161857A5054E38L, 0x6A0E7DA4527436D1L, 0x5BD86A381CDE9FF2L, 0xCAF7756231770C32L,
+ 0xB09AAED9E279C8D0L, 0x5DEF1091C60674DBL, 0x111046A2515E5045L, 0x23536CE4729802FCL,
+ 0xC50CBCF7F5B63CFAL, 0x73A16887CD171F03L, 0x7D2941AFD9F28DBDL, 0x3F5E3EB45A4F3B9DL,
+ 0x84EEFE361B677140L, 0x3DB8E3D3E7076271L, 0x1A3A28F9F20FD248L, 0x7EBC7C75B49E7627L,
+ 0x74E5F293C7EB565CL, 0x18DCF59E4F478BA4L, 0x0C6EF44FA9ADCB52L, 0xC699812D98DAC760L,
+ 0x788B06DC6E469D0EL, 0xFC65F8EA7521EC4EL, 0x30A5F7219E8E0B55L, 0x2BEC3F65BCA57B6BL,
+ 0xDDD04969BAF1B75EL, 0x99904CDBE394EA57L, 0x14B201D1E6EA40F6L, 0xBBB0C08241284ADDL,
+ 0x50F20463BF8F1DFFL, 0xE8D7F93B93CBACB8L, 0x4D8CB68E477C86E8L, 0xC1DD1B3992268E3FL,
+ 0x7C5AA11209D62FCBL, 0x2F3D98ABDB35C9AEL, 0x671369562BFD5FF5L, 0x15C1E16C36CEE280L,
+ 0x1D7EB2EDF8F39B17L, 0xDA94D37DB00DFE01L, 0x877BC3EC760B8ADAL, 0xCB8495DFE153AE44L,
+ 0x05A24773B7B410B3L, 0x12857B783C32ABDFL, 0x8EB770D06812513BL, 0x536739B9D2E3E665L,
+ 0x584D57E271B26468L, 0xD789C78FC9849725L, 0xA935BBFA7D1AE102L, 0x8B1537A3DFA64188L,
+ 0xD0CD5D9BC378DE7AL, 0x4AC82C9A4D80CFB7L, 0x42777F1B83BDB620L, 0x72D2883A1D33BD75L,
+ 0x5E7A2D4BAB6A8F41L, 0xF4DAAB6BBB1C95D9L, 0x905CFFE7FD8D31B6L, 0x83AA6422119B381FL,
+ 0xC0AEFB8442022C49L, 0xA0F908C663033AE3L, 0xA428AF0804938826L, 0xADE41C341A8A53C7L,
+ 0xAE7121EE77E6A85DL, 0xC47F5C4A25929E8CL, 0xB538E9AA55CDD863L, 0x06377AA9DAD8EB29L,
+ 0xA18AE87BB3279895L, 0x6EDFDA6A35E48414L, 0x6B7D9D19825094A7L, 0xD41CFA55A4E86CBFL,
+ 0xE5CAEDC9EA42C59CL, 0xA36C351C0E6FC179L, 0x5181E4DE6FABBF89L, 0xFFF0C530184D17D4L,
+ 0x9D41EB1584045892L, 0x1C0D525028D73961L, 0xF178EC180CA8856AL, 0x9A0571018EF811CDL,
+ 0x4091A27C3EF5EFCCL, 0x19AF15239F6329D2L, 0x347450EFF91EB990L, 0xE11B4A078DD27759L,
+ 0xB9561DE5FC601331L, 0x912F1F5A2DA993C0L, 0x1654DCB65BA2191AL, 0x3E2DDE098A6B99EBL,
+ 0x8A66D71E0F82E3FEL, 0x8C51ADB7D55A08D7L, 0x4533E50F8941FF7FL, 0x02E6DD67BD4859ECL,
+ 0xE068AABA5DF6D52FL, 0xC24826E3FF4A75A5L, 0x6C39070D88ACDDF8L, 0x6486548C4691A46FL,
+ 0xD1BEBD26135C7C0CL, 0xB30F93038F15334AL, 0x82D9849FC1BF9A69L, 0x9C320BA85420FAE4L,
+ 0xFA528243AFF90767L, 0x9ED4D6CFE968A308L, 0xB825FD582C44B147L, 0x9B7691BC5EDCB3BBL,
+ 0xC7EA619048FE6516L, 0x1063A61F817AF233L, 0x47D538683409A693L, 0x63C2CE984C6DED30L,
+ 0x2A9FDFD86C81D91DL, 0x7B1E3B06032A6694L, 0x666089EBFBD9FD83L, 0x0A598EE67375207BL,
+ 0x07449A140AFC495FL, 0x2CA8A571B6593234L, 0x1F986F8A45BBC2FBL, 0x381AA4A050B372C2L,
+ 0x5423A3ADD81FAF3AL, 0x17273C0B8B86BB6CL, 0xFE83258DC869B5A2L, 0x287902BFD1C980F1L,
+ 0xF5A94BD66B3837AFL, 0x88800A79B2CABA12L, 0x55504310083B0D4CL, 0xDF36940E07B9EEB2L,
+ 0x04D1A7CE6790B2C5L, 0x612413FFF125B4DCL, 0x26F12B97C52C124FL, 0x86082351A62F28ACL,
+ 0xEF93632F9937E5E7L, 0x3507B052293A1BE6L, 0xE72C30AE570A9C70L, 0xD3586041AE1425E0L,
+ 0xDE4574B3D79D4CC4L, 0x92BA228040C5685AL, 0xF00B0CA5DC8C271CL, 0xBE1287F1F69C5A6EL,
+ 0xF39E317FB1E0DC86L, 0x495D114020EC342DL, 0x699B407E3F18CD4BL, 0xDCA3A9D46AD51528L,
+ 0x0D1D14F279896924L, 0x0000000000000000L, 0x593EB75FA196C61EL, 0x2E4E78160B116BD8L,
+ 0x6D4AE7B058887F8EL, 0xE65FD013872E3E06L, 0x7A6DDBBBD30EC4E2L, 0xAC97FC89CAAEF1B1L,
+ 0x09CCB33C1E19DBE1L, 0x89F3EAC462EE1864L, 0x7770CF49AA87ADC6L, 0x56C57ECA6557F6D6L,
+ 0x03953DDA6D6CFB9AL, 0x36928D884456E07CL, 0x1EEB8F37959F608DL, 0x31D6179C4EAAA923L,
+ 0x6FAC3AD7E5C02662L, 0x43049FA653991456L, 0xABD3669DC052B8EEL, 0xAF02C153A7C20A2BL,
+ 0x3CCB036E3723C007L, 0x93C9C23D90E1CA2CL, 0xC33BC65E2F6ED7D3L, 0x4CFF56339758249EL,
+ 0xB1E94E64325D6AA6L, 0x37E16D359472420AL, 0x79F8E661BE623F78L, 0x5214D90402C74413L,
+ 0x482EF1FDF0C8965BL, 0x13F69BC5EC1609A9L, 0x0E88292814E592BEL, 0x4E198B542A107D72L,
+ 0xCCC00FCBEBAFE71BL, 0x1B49C844222B703EL, 0x2564164DA840E9D5L, 0x20C6513E1FF4F966L,
+ 0xBAC3203F910CE8ABL, 0xF2EDD1C261C47EF0L, 0x814CB945ACD361F3L, 0x95FEB8944A392105L,
+ 0x5C9CF02C1622D6ADL, 0x971865F3F77178E9L, 0xBD87BA2B9BF0A1F4L, 0x444005B259655D09L,
+ 0xED75BE48247FBC0BL, 0x7596122E17CFF42AL, 0xB44B091785E97A15L, 0x966B854E2755DA9FL,
+ 0xEEE0839249134791L, 0x32432A4623C652B9L, 0xA8465B47AD3E4374L, 0xF8B45F2412B15E8BL,
+ 0x2417F6F078644BA3L, 0xFB2162FE7FDDA511L, 0x4BBBCC279DA46DC1L, 0x0173E0BDD024A276L,
+ 0x22208C59A2BCA08AL, 0x8FC4906DB836F34DL, 0xE4B90D743A6667EAL, 0x7147B5E0705F46EFL,
+ 0x2782CB2A1508B039L, 0xEC065EF5F45B1E7DL, 0x21B5B183CFD05B10L, 0xDBE733C060295C77L,
+ 0x9FA73672394C017EL, 0xCF55321186C31C81L, 0xD8720E1A0D45A7EDL, 0x3B8F997A3DDF8958L,
+ 0x3AFC79C7EDFB2B2EL, 0xE9A4198643EF0ECEL, 0x5F09CDF67B4E2D37L, 0x4F6A6BE9FA34DF04L,
+ 0xB6ADD47038A123F9L, 0x8D224D0A057EAAA1L, 0xC96248B85C1BF7A8L, 0xE3FD9760309A2EB5L,
+ 0x0B2A6E5BA351820DL, 0xEB42C4E1FEA75722L, 0x948D58299A1D8373L, 0x7FCF9CC864BAD451L,
+ 0xA55B4FB5D4B72A50L, 0x08BF5381CE3D7997L, 0x46A6D8D5E42D04E5L, 0xD22B80FC7E308796L,
+ 0x57B69E77B57354A0L, 0x3969441D8097D0B4L, 0x3330CAFBF3E2F0CFL, 0xE28E77DDE0BE8CC3L,
+ 0x62B12E259C494F46L, 0xA6CE726FB9DBD1CAL, 0x41E242C1EED14DBAL, 0x76032FF47AA30FB0L
+ },
+ {
+ 0x45B268A93ACDE4CCL, 0xAF7F0BE884549D08L, 0x048354B3C1468263L, 0x925435C2C80EFED2L,
+ 0xEE4E37F27FDFFBA7L, 0x167A33920C60F14DL, 0xFB123B52EA03E584L, 0x4A0CAB53FDBB9007L,
+ 0x9DEAF6380F788A19L, 0xCB48EC558F0CB32AL, 0xB59DC4B2D6FEF7E0L, 0xDCDBCA22F4F3ECB6L,
+ 0x11DF5813549A9C40L, 0xE33FDEDF568ACED3L, 0xA0C1C8124322E9C3L, 0x07A56B8158FA6D0DL,
+ 0x77279579B1E1F3DDL, 0xD9B18B74422AC004L, 0xB8EC2D9FFFABC294L, 0xF4ACF8A82D75914FL,
+ 0x7BBF69B1EF2B6878L, 0xC4F62FAF487AC7E1L, 0x76CE809CC67E5D0CL, 0x6711D88F92E4C14CL,
+ 0x627B99D9243DEDFEL, 0x234AA5C3DFB68B51L, 0x909B1F15262DBF6DL, 0x4F66EA054B62BCB5L,
+ 0x1AE2CF5A52AA6AE8L, 0xBEA053FBD0CE0148L, 0xED6808C0E66314C9L, 0x43FE16CD15A82710L,
+ 0xCD049231A06970F6L, 0xE7BC8A6C97CC4CB0L, 0x337CE835FCB3B9C0L, 0x65DEF2587CC780F3L,
+ 0x52214EDE4132BB50L, 0x95F15E4390F493DFL, 0x870839625DD2E0F1L, 0x41313C1AFB8B66AFL,
+ 0x91720AF051B211BCL, 0x477D427ED4EEA573L, 0x2E3B4CEEF6E3BE25L, 0x82627834EB0BCC43L,
+ 0x9C03E3DD78E724C8L, 0x2877328AD9867DF9L, 0x14B51945E243B0F2L, 0x574B0F88F7EB97E2L,
+ 0x88B6FA989AA4943AL, 0x19C4F068CB168586L, 0x50EE6409AF11FAEFL, 0x7DF317D5C04EABA4L,
+ 0x7A567C5498B4C6A9L, 0xB6BBFB804F42188EL, 0x3CC22BCF3BC5CD0BL, 0xD04336EAAA397713L,
+ 0xF02FAC1BEC33132CL, 0x2506DBA7F0D3488DL, 0xD7E65D6BF2C31A1EL, 0x5EB9B2161FF820F5L,
+ 0x842E0650C46E0F9FL, 0x716BEB1D9E843001L, 0xA933758CAB315ED4L, 0x3FE414FDA2792265L,
+ 0x27C9F1701EF00932L, 0x73A4C1CA70A771BEL, 0x94184BA6E76B3D0EL, 0x40D829FF8C14C87EL,
+ 0x0FBEC3FAC77674CBL, 0x3616A9634A6A9572L, 0x8F139119C25EF937L, 0xF545ED4D5AEA3F9EL,
+ 0xE802499650BA387BL, 0x6437E7BD0B582E22L, 0xE6559F89E053E261L, 0x80AD52E305288DFCL,
+ 0x6DC55A23E34B9935L, 0xDE14E0F51AD0AD09L, 0xC6390578A659865EL, 0x96D7617109487CB1L,
+ 0xE2D6CB3A21156002L, 0x01E915E5779FAED1L, 0xADB0213F6A77DCB7L, 0x9880B76EB9A1A6ABL,
+ 0x5D9F8D248644CF9BL, 0xFD5E4536C5662658L, 0xF1C6B9FE9BACBDFDL, 0xEACD6341BE9979C4L,
+ 0xEFA7221708405576L, 0x510771ECD88E543EL, 0xC2BA51CB671F043DL, 0x0AD482AC71AF5879L,
+ 0xFE787A045CDAC936L, 0xB238AF338E049AEDL, 0xBD866CC94972EE26L, 0x615DA6EBBD810290L,
+ 0x3295FDD08B2C1711L, 0xF834046073BF0AEAL, 0xF3099329758FFC42L, 0x1CAEB13E7DCFA934L,
+ 0xBA2307481188832BL, 0x24EFCE42874CE65CL, 0x0E57D61FB0E9DA1AL, 0xB3D1BAD6F99B343CL,
+ 0xC0757B1C893C4582L, 0x2B510DB8403A9297L, 0x5C7698C1F1DB614AL, 0x3E0D0118D5E68CB4L,
+ 0xD60F488E855CB4CFL, 0xAE961E0DF3CB33D9L, 0x3A8E55AB14A00ED7L, 0x42170328623789C1L,
+ 0x838B6DD19C946292L, 0x895FEF7DED3B3AEBL, 0xCFCBB8E64E4A3149L, 0x064C7E642F65C3DCL,
+ 0x3D2B3E2A4C5A63DAL, 0x5BD3F340A9210C47L, 0xB474D157A1615931L, 0xAC5934DA1DE87266L,
+ 0x6EE365117AF7765BL, 0xC86ED36716B05C44L, 0x9BA6885C201D49C5L, 0xB905387A88346C45L,
+ 0x131072C4BAB9DDFFL, 0xBF49461EA751AF99L, 0xD52977BC1CE05BA1L, 0xB0F785E46027DB52L,
+ 0x546D30BA6E57788CL, 0x305AD707650F56AEL, 0xC987C682612FF295L, 0xA5AB8944F5FBC571L,
+ 0x7ED528E759F244CAL, 0x8DDCBBCE2C7DB888L, 0xAA154ABE328DB1BAL, 0x1E619BE993ECE88BL,
+ 0x09F2BD9EE813B717L, 0x7401AA4B285D1CB3L, 0x21858F143195CAEEL, 0x48C381841398D1B8L,
+ 0xFCB750D3B2F98889L, 0x39A86A998D1CE1B9L, 0x1F888E0CE473465AL, 0x7899568376978716L,
+ 0x02CF2AD7EE2341BFL, 0x85C713B5B3F1A14EL, 0xFF916FE12B4567E7L, 0x7C1A0230B7D10575L,
+ 0x0C98FCC85ECA9BA5L, 0xA3E7F720DA9E06ADL, 0x6A6031A2BBB1F438L, 0x973E74947ED7D260L,
+ 0x2CF4663918C0FF9AL, 0x5F50A7F368678E24L, 0x34D983B4A449D4CDL, 0x68AF1B755592B587L,
+ 0x7F3C3D022E6DEA1BL, 0xABFC5F5B45121F6BL, 0x0D71E92D29553574L, 0xDFFDF5106D4F03D8L,
+ 0x081BA87B9F8C19C6L, 0xDB7EA1A3AC0981BBL, 0xBBCA12AD66172DFAL, 0x79704366010829C7L,
+ 0x179326777BFF5F9CL, 0x0000000000000000L, 0xEB2476A4C906D715L, 0x724DD42F0738DF6FL,
+ 0xB752EE6538DDB65FL, 0x37FFBC863DF53BA3L, 0x8EFA84FCB5C157E6L, 0xE9EB5C73272596AAL,
+ 0x1B0BDABF2535C439L, 0x86E12C872A4D4E20L, 0x9969A28BCE3E087AL, 0xFAFB2EB79D9C4B55L,
+ 0x056A4156B6D92CB2L, 0x5A3AE6A5DEBEA296L, 0x22A3B026A8292580L, 0x53C85B3B36AD1581L,
+ 0xB11E900117B87583L, 0xC51F3A4A3FE56930L, 0xE019E1EDCF3621BDL, 0xEC811D2591FCBA18L,
+ 0x445B7D4C4D524A1DL, 0xA8DA6069DCAEF005L, 0x58F5CC72309DE329L, 0xD4C062596B7FF570L,
+ 0xCE22AD0339D59F98L, 0x591CD99747024DF8L, 0x8B90C5AA03187B54L, 0xF663D27FC356D0F0L,
+ 0xD8589E9135B56ED5L, 0x35309651D3D67A1CL, 0x12F96721CD26732EL, 0xD28C1C3D441A36ACL,
+ 0x492A946164077F69L, 0x2D1D73DC6F5F514BL, 0x6F0A70F40D68D88AL, 0x60B4B30ECA1EAC41L,
+ 0xD36509D83385987DL, 0x0B3D97490630F6A8L, 0x9ECCC90A96C46577L, 0xA20EE2C5AD01A87CL,
+ 0xE49AB55E0E70A3DEL, 0xA4429CA182646BA0L, 0xDA97B446DB962F6AL, 0xCCED87D4D7F6DE27L,
+ 0x2AB8185D37A53C46L, 0x9F25DCEFE15BCBA6L, 0xC19C6EF9FEA3EB53L, 0xA764A3931BD884CEL,
+ 0x2FD2590B817C10F4L, 0x56A21A6D80743933L, 0xE573A0BB79EF0D0FL, 0x155C0CA095DC1E23L,
+ 0x6C2C4FC694D437E4L, 0x10364DF623053291L, 0xDD32DFC7836C4267L, 0x03263F3299BCEF6EL,
+ 0x66F8CD6AE57B6F9DL, 0x8C35AE2B5BE21659L, 0x31B3C2E21290F87FL, 0x93BD2027BF915003L,
+ 0x69460E90220D1B56L, 0x299E276FAE19D328L, 0x63928C3C53A2432FL, 0x7082FEF8E91B9ED0L,
+ 0xBC6F792C3EED40F7L, 0x4C40D537D2DE53DBL, 0x75E8BFAE5FC2B262L, 0x4DA9C0D2A541FD0AL,
+ 0x4E8FFFE03CFD1264L, 0x2620E495696FA7E3L, 0xE1F0F408B8A98F6CL, 0xD1AA230FDDA6D9C2L,
+ 0xC7D0109DD1C6288FL, 0x8A79D04F7487D585L, 0x4694579BA3710BA2L, 0x38417F7CFA834F68L,
+ 0x1D47A4DB0A5007E5L, 0x206C9AF1460A643FL, 0xA128DDF734BD4712L, 0x8144470672B7232DL,
+ 0xF2E086CC02105293L, 0x182DE58DBC892B57L, 0xCAA1F9B0F8931DFBL, 0x6B892447CC2E5AE9L,
+ 0xF9DD11850420A43BL, 0x4BE5BEB68A243ED6L, 0x5584255F19C8D65DL, 0x3B67404E633FA006L,
+ 0xA68DB6766C472A1FL, 0xF78AC79AB4C97E21L, 0xC353442E1080AAECL, 0x9A4F9DB95782E714L
+ },
+ {
+ 0x05BA7BC82C9B3220L, 0x31A54665F8B65E4FL, 0xB1B651F77547F4D4L, 0x8BFA0D857BA46682L,
+ 0x85A96C5AA16A98BBL, 0x990FAEF908EB79C9L, 0xA15E37A247F4A62DL, 0x76857DCD5D27741EL,
+ 0xF8C50B800A1820BCL, 0xBE65DCB201F7A2B4L, 0x666D1B986F9426E7L, 0x4CC921BF53C4E648L,
+ 0x95410A0F93D9CA42L, 0x20CDCCAA647BA4EFL, 0x429A4060890A1871L, 0x0C4EA4F69B32B38BL,
+ 0xCCDA362DDE354CD3L, 0x96DC23BC7C5B2FA9L, 0xC309BB68AA851AB3L, 0xD26131A73648E013L,
+ 0x021DC52941FC4DB2L, 0xCD5ADAB7704BE48AL, 0xA77965D984ED71E6L, 0x32386FD61734BBA4L,
+ 0xE82D6DD538AB7245L, 0x5C2147EA6177B4B1L, 0x5DA1AB70CF091CE8L, 0xAC907FCE72B8BDFFL,
+ 0x57C85DFD972278A8L, 0xA4E44C6A6B6F940DL, 0x3851995B4F1FDFE4L, 0x62578CCAED71BC9EL,
+ 0xD9882BB0C01D2C0AL, 0x917B9D5D113C503BL, 0xA2C31E11A87643C6L, 0xE463C923A399C1CEL,
+ 0xF71686C57EA876DCL, 0x87B4A973E096D509L, 0xAF0D567D9D3A5814L, 0xB40C2A3F59DCC6F4L,
+ 0x3602F88495D121DDL, 0xD3E1DD3D9836484AL, 0xF945E71AA46688E5L, 0x7518547EB2A591F5L,
+ 0x9366587450C01D89L, 0x9EA81018658C065BL, 0x4F54080CBC4603A3L, 0x2D0384C65137BF3DL,
+ 0xDC325078EC861E2AL, 0xEA30A8FC79573FF7L, 0x214D2030CA050CB6L, 0x65F0322B8016C30CL,
+ 0x69BE96DD1B247087L, 0xDB95EE9981E161B8L, 0xD1FC1814D9CA05F8L, 0x820ED2BBCC0DE729L,
+ 0x63D76050430F14C7L, 0x3BCCB0E8A09D3A0FL, 0x8E40764D573F54A2L, 0x39D175C1E16177BDL,
+ 0x12F5A37C734F1F4BL, 0xAB37C12F1FDFC26DL, 0x5648B167395CD0F1L, 0x6C04ED1537BF42A7L,
+ 0xED97161D14304065L, 0x7D6C67DAAB72B807L, 0xEC17FA87BA4EE83CL, 0xDFAF79CB0304FBC1L,
+ 0x733F060571BC463EL, 0x78D61C1287E98A27L, 0xD07CF48E77B4ADA1L, 0xB9C262536C90DD26L,
+ 0xE2449B5860801605L, 0x8FC09AD7F941FCFBL, 0xFAD8CEA94BE46D0EL, 0xA343F28B0608EB9FL,
+ 0x9B126BD04917347BL, 0x9A92874AE7699C22L, 0x1B017C42C4E69EE0L, 0x3A4C5C720EE39256L,
+ 0x4B6E9F5E3EA399DAL, 0x6BA353F45AD83D35L, 0xE7FEE0904C1B2425L, 0x22D009832587E95DL,
+ 0x842980C00F1430E2L, 0xC6B3C0A0861E2893L, 0x087433A419D729F2L, 0x341F3DADD42D6C6FL,
+ 0xEE0A3FAEFBB2A58EL, 0x4AEE73C490DD3183L, 0xAAB72DB5B1A16A34L, 0xA92A04065E238FDFL,
+ 0x7B4B35A1686B6FCCL, 0x6A23BF6EF4A6956CL, 0x191CB96B851AD352L, 0x55D598D4D6DE351AL,
+ 0xC9604DE5F2AE7EF3L, 0x1CA6C2A3A981E172L, 0xDE2F9551AD7A5398L, 0x3025AAFF56C8F616L,
+ 0x15521D9D1E2860D9L, 0x506FE31CFA45073AL, 0x189C55F12B647B0BL, 0x0180EC9AAE7EA859L,
+ 0x7CEC8B40050C105EL, 0x2350E5198BF94104L, 0xEF8AD33455CC0DD7L, 0x07A7BEE16D677F92L,
+ 0xE5E325B90DE76997L, 0x5A061591A26E637AL, 0xB611EF1618208B46L, 0x09F4DF3EB7A981ABL,
+ 0x1EBB078AE87DACC0L, 0xB791038CB65E231FL, 0x0FD38D4574B05660L, 0x67EDF702C1EA8EBEL,
+ 0xBA5F4BE0831238CDL, 0xE3C477C2CEFEBE5CL, 0x0DCE486C354C1BD2L, 0x8C5DB36416C31910L,
+ 0x26EA9ED1A7627324L, 0x039D29B3EF82E5EBL, 0x9F28FC82CBF2AE02L, 0xA8AAE89CF05D2786L,
+ 0x431AACFA2774B028L, 0xCF471F9E31B7A938L, 0x581BD0B8E3922EC8L, 0xBC78199B400BEF06L,
+ 0x90FB71C7BF42F862L, 0x1F3BEB1046030499L, 0x683E7A47B55AD8DEL, 0x988F4263A695D190L,
+ 0xD808C72A6E638453L, 0x0627527BC319D7CBL, 0xEBB04466D72997AEL, 0xE67E0C0AE2658C7CL,
+ 0x14D2F107B056C880L, 0x7122C32C30400B8CL, 0x8A7AE11FD5DACEDBL, 0xA0DEDB38E98A0E74L,
+ 0xAD109354DCC615A6L, 0x0BE91A17F655CC19L, 0x8DDD5FFEB8BDB149L, 0xBFE53028AF890AEDL,
+ 0xD65BA6F5B4AD7A6AL, 0x7956F0882997227EL, 0x10E8665532B352F9L, 0x0E5361DFDACEFE39L,
+ 0xCEC7F3049FC90161L, 0xFF62B561677F5F2EL, 0x975CCF26D22587F0L, 0x51EF0F86543BAF63L,
+ 0x2F1E41EF10CBF28FL, 0x52722635BBB94A88L, 0xAE8DBAE73344F04DL, 0x410769D36688FD9AL,
+ 0xB3AB94DE34BBB966L, 0x801317928DF1AA9BL, 0xA564A0F0C5113C54L, 0xF131D4BEBDB1A117L,
+ 0x7F71A2F3EA8EF5B5L, 0x40878549C8F655C3L, 0x7EF14E6944F05DECL, 0xD44663DCF55137D8L,
+ 0xF2ACFD0D523344FCL, 0x0000000000000000L, 0x5FBC6E598EF5515AL, 0x16CF342EF1AA8532L,
+ 0xB036BD6DDB395C8DL, 0x13754FE6DD31B712L, 0xBBDFA77A2D6C9094L, 0x89E7C8AC3A582B30L,
+ 0x3C6B0E09CDFA459DL, 0xC4AE0589C7E26521L, 0x49735A777F5FD468L, 0xCAFD64561D2C9B18L,
+ 0xDA1502032F9FC9E1L, 0x8867243694268369L, 0x3782141E3BAF8984L, 0x9CB5D53124704BE9L,
+ 0xD7DB4A6F1AD3D233L, 0xA6F989432A93D9BFL, 0x9D3539AB8A0EE3B0L, 0x53F2CAAF15C7E2D1L,
+ 0x6E19283C76430F15L, 0x3DEBE2936384EDC4L, 0x5E3C82C3208BF903L, 0x33B8834CB94A13FDL,
+ 0x6470DEB12E686B55L, 0x359FD1377A53C436L, 0x61CAA57902F35975L, 0x043A975282E59A79L,
+ 0xFD7F70482683129CL, 0xC52EE913699CCD78L, 0x28B9FF0E7DAC8D1DL, 0x5455744E78A09D43L,
+ 0xCB7D88CCB3523341L, 0x44BD121B4A13CFBAL, 0x4D49CD25FDBA4E11L, 0x3E76CB208C06082FL,
+ 0x3FF627BA2278A076L, 0xC28957F204FBB2EAL, 0x453DFE81E46D67E3L, 0x94C1E6953DA7621BL,
+ 0x2C83685CFF491764L, 0xF32C1197FC4DECA5L, 0x2B24D6BD922E68F6L, 0xB22B78449AC5113FL,
+ 0x48F3B6EDD1217C31L, 0x2E9EAD75BEB55AD6L, 0x174FD8B45FD42D6BL, 0x4ED4E4961238ABFAL,
+ 0x92E6B4EEFEBEB5D0L, 0x46A0D7320BEF8208L, 0x47203BA8A5912A51L, 0x24F75BF8E69E3E96L,
+ 0xF0B1382413CF094EL, 0xFEE259FBC901F777L, 0x276A724B091CDB7DL, 0xBDF8F501EE75475FL,
+ 0x599B3C224DEC8691L, 0x6D84018F99C1EAFEL, 0x7498B8E41CDB39ACL, 0xE0595E71217C5BB7L,
+ 0x2AA43A273C50C0AFL, 0xF50B43EC3F543B6EL, 0x838E3E2162734F70L, 0xC09492DB4507FF58L,
+ 0x72BFEA9FDFC2EE67L, 0x11688ACF9CCDFAA0L, 0x1A8190D86A9836B9L, 0x7ACBD93BC615C795L,
+ 0xC7332C3A286080CAL, 0x863445E94EE87D50L, 0xF6966A5FD0D6DE85L, 0xE9AD814F96D5DA1CL,
+ 0x70A22FB69E3EA3D5L, 0x0A69F68D582B6440L, 0xB8428EC9C2EE757FL, 0x604A49E3AC8DF12CL,
+ 0x5B86F90B0C10CB23L, 0xE1D9B2EB8F02F3EEL, 0x29391394D3D22544L, 0xC8E0A17F5CD0D6AAL,
+ 0xB58CC6A5F7A26EADL, 0x8193FB08238F02C2L, 0xD5C68F465B2F9F81L, 0xFCFF9CD288FDBAC5L,
+ 0x77059157F359DC47L, 0x1D262E3907FF492BL, 0xFB582233E59AC557L, 0xDDB2BCE242F8B673L,
+ 0x2577B76248E096CFL, 0x6F99C4A6D83DA74CL, 0xC1147E41EB795701L, 0xF48BAF76912A9337L
+ },
+ {
+ 0x3EF29D249B2C0A19L, 0xE9E16322B6F8622FL, 0x5536994047757F7AL, 0x9F4D56D5A47B0B33L,
+ 0x822567466AA1174CL, 0xB8F5057DEB082FB2L, 0xCC48C10BF4475F53L, 0x373088D4275DEC3AL,
+ 0x968F4325180AED10L, 0x173D232CF7016151L, 0xAE4ED09F946FCC13L, 0xFD4B4741C4539873L,
+ 0x1B5B3F0DD9933765L, 0x2FFCB0967B644052L, 0xE02376D20A89840CL, 0xA3AE3A70329B18D7L,
+ 0x419CBD2335DE8526L, 0xFAFEBF115B7C3199L, 0x0397074F85AA9B0DL, 0xC58AD4FB4836B970L,
+ 0xBEC60BE3FC4104A8L, 0x1EFF36DC4B708772L, 0x131FDC33ED8453B6L, 0x0844E33E341764D3L,
+ 0x0FF11B6EAB38CD39L, 0x64351F0A7761B85AL, 0x3B5694F509CFBA0EL, 0x30857084B87245D0L,
+ 0x47AFB3BD2297AE3CL, 0xF2BA5C2F6F6B554AL, 0x74BDC4761F4F70E1L, 0xCFDFC64471EDC45EL,
+ 0xE610784C1DC0AF16L, 0x7ACA29D63C113F28L, 0x2DED411776A859AFL, 0xAC5F211E99A3D5EEL,
+ 0xD484F949A87EF33BL, 0x3CE36CA596E013E4L, 0xD120F0983A9D432CL, 0x6BC40464DC597563L,
+ 0x69D5F5E5D1956C9EL, 0x9AE95F043698BB24L, 0xC9ECC8DA66A4EF44L, 0xD69508C8A5B2EAC6L,
+ 0xC40C2235C0503B80L, 0x38C193BA8C652103L, 0x1CEEC75D46BC9E8FL, 0xD331011937515AD1L,
+ 0xD8E2E56886ECA50FL, 0xB137108D5779C991L, 0x709F3B6905CA4206L, 0x4FEB50831680CAEFL,
+ 0xEC456AF3241BD238L, 0x58D673AFE181ABBEL, 0x242F54E7CAD9BF8CL, 0x0211F1810DCC19FDL,
+ 0x90BC4DBB0F43C60AL, 0x9518446A9DA0761DL, 0xA1BFCBF13F57012AL, 0x2BDE4F8961E172B5L,
+ 0x27B853A84F732481L, 0xB0B1E643DF1F4B61L, 0x18CC38425C39AC68L, 0xD2B7F7D7BF37D821L,
+ 0x3103864A3014C720L, 0x14AA246372ABFA5CL, 0x6E600DB54EBAC574L, 0x394765740403A3F3L,
+ 0x09C215F0BC71E623L, 0x2A58B947E987F045L, 0x7B4CDF18B477BDD8L, 0x9709B5EB906C6FE0L,
+ 0x73083C268060D90BL, 0xFEDC400E41F9037EL, 0x284948C6E44BE9B8L, 0x728ECAE808065BFBL,
+ 0x06330E9E17492B1AL, 0x5950856169E7294EL, 0xBAE4F4FCE6C4364FL, 0xCA7BCF95E30E7449L,
+ 0x7D7FD186A33E96C2L, 0x52836110D85AD690L, 0x4DFAA1021B4CD312L, 0x913ABB75872544FAL,
+ 0xDD46ECB9140F1518L, 0x3D659A6B1E869114L, 0xC23F2CABD719109AL, 0xD713FE062DD46836L,
+ 0xD0A60656B2FBC1DCL, 0x221C5A79DD909496L, 0xEFD26DBCA1B14935L, 0x0E77EDA0235E4FC9L,
+ 0xCBFD395B6B68F6B9L, 0x0DE0EAEFA6F4D4C4L, 0x0422FF1F1A8532E7L, 0xF969B85EDED6AA94L,
+ 0x7F6E2007AEF28F3FL, 0x3AD0623B81A938FEL, 0x6624EE8B7AADA1A7L, 0xB682E8DDC856607BL,
+ 0xA78CC56F281E2A30L, 0xC79B257A45FAA08DL, 0x5B4174E0642B30B3L, 0x5F638BFF7EAE0254L,
+ 0x4BC9AF9C0C05F808L, 0xCE59308AF98B46AEL, 0x8FC58DA9CC55C388L, 0x803496C7676D0EB1L,
+ 0xF33CAAE1E70DD7BAL, 0xBB6202326EA2B4BFL, 0xD5020F87201871CBL, 0x9D5CA754A9B712CEL,
+ 0x841669D87DE83C56L, 0x8A6184785EB6739FL, 0x420BBA6CB0741E2BL, 0xF12D5B60EAC1CE47L,
+ 0x76AC35F71283691CL, 0x2C6BB7D9FECEDB5FL, 0xFCCDB18F4C351A83L, 0x1F79C012C3160582L,
+ 0xF0ABADAE62A74CB7L, 0xE1A5801C82EF06FCL, 0x67A21845F2CB2357L, 0x5114665F5DF04D9DL,
+ 0xBF40FD2D74278658L, 0xA0393D3FB73183DAL, 0x05A409D192E3B017L, 0xA9FB28CF0B4065F9L,
+ 0x25A9A22942BF3D7CL, 0xDB75E22703463E02L, 0xB326E10C5AB5D06CL, 0xE7968E8295A62DE6L,
+ 0xB973F3B3636EAD42L, 0xDF571D3819C30CE5L, 0xEE549B7229D7CBC5L, 0x12992AFD65E2D146L,
+ 0xF8EF4E9056B02864L, 0xB7041E134030E28BL, 0xC02EDD2ADAD50967L, 0x932B4AF48AE95D07L,
+ 0x6FE6FB7BC6DC4784L, 0x239AACB755F61666L, 0x401A4BEDBDB807D6L, 0x485EA8D389AF6305L,
+ 0xA41BC220ADB4B13DL, 0x753B32B89729F211L, 0x997E584BB3322029L, 0x1D683193CEDA1C7FL,
+ 0xFF5AB6C0C99F818EL, 0x16BBD5E27F67E3A1L, 0xA59D34EE25D233CDL, 0x98F8AE853B54A2D9L,
+ 0x6DF70AFACB105E79L, 0x795D2E99B9BBA425L, 0x8E437B6744334178L, 0x0186F6CE886682F0L,
+ 0xEBF092A3BB347BD2L, 0xBCD7FA62F18D1D55L, 0xADD9D7D011C5571EL, 0x0BD3E471B1BDFFDEL,
+ 0xAA6C2F808EEAFEF4L, 0x5EE57D31F6C880A4L, 0xF50FA47FF044FCA0L, 0x1ADDC9C351F5B595L,
+ 0xEA76646D3352F922L, 0x0000000000000000L, 0x85909F16F58EBEA6L, 0x46294573AAF12CCCL,
+ 0x0A5512BF39DB7D2EL, 0x78DBD85731DD26D5L, 0x29CFBE086C2D6B48L, 0x218B5D36583A0F9BL,
+ 0x152CD2ADFACD78ACL, 0x83A39188E2C795BCL, 0xC3B9DA655F7F926AL, 0x9ECBA01B2C1D89C3L,
+ 0x07B5F8509F2FA9EAL, 0x7EE8D6C926940DCFL, 0x36B67E1AAF3B6ECAL, 0x86079859702425ABL,
+ 0xFB7849DFD31AB369L, 0x4C7C57CC932A51E2L, 0xD96413A60E8A27FFL, 0x263EA566C715A671L,
+ 0x6C71FC344376DC89L, 0x4A4F595284637AF8L, 0xDAF314E98B20BCF2L, 0x572768C14AB96687L,
+ 0x1088DB7C682EC8BBL, 0x887075F9537A6A62L, 0x2E7A4658F302C2A2L, 0x619116DBE582084DL,
+ 0xA87DDE018326E709L, 0xDCC01A779C6997E8L, 0xEDC39C3DAC7D50C8L, 0xA60A33A1A078A8C0L,
+ 0xC1A82BE452B38B97L, 0x3F746BEA134A88E9L, 0xA228CCBEBAFD9A27L, 0xABEAD94E068C7C04L,
+ 0xF48952B178227E50L, 0x5CF48CB0FB049959L, 0x6017E0156DE48ABDL, 0x4438B4F2A73D3531L,
+ 0x8C528AE649FF5885L, 0xB515EF924DFCFB76L, 0x0C661C212E925634L, 0xB493195CC59A7986L,
+ 0x9CDA519A21D1903EL, 0x32948105B5BE5C2DL, 0x194ACE8CD45F2E98L, 0x438D4CA238129CDBL,
+ 0x9B6FA9CABEFE39D4L, 0x81B26009EF0B8C41L, 0xDED1EBF691A58E15L, 0x4E6DA64D9EE6481FL,
+ 0x54B06F8ECF13FD8AL, 0x49D85E1D01C9E1F5L, 0xAFC826511C094EE3L, 0xF698A33075EE67ADL,
+ 0x5AC7822EEC4DB243L, 0x8DD47C28C199DA75L, 0x89F68337DB1CE892L, 0xCDCE37C57C21DDA3L,
+ 0x530597DE503C5460L, 0x6A42F2AA543FF793L, 0x5D727A7E73621BA9L, 0xE232875307459DF1L,
+ 0x56A19E0FC2DFE477L, 0xC61DD3B4CD9C227DL, 0xE5877F03986A341BL, 0x949EB2A415C6F4EDL,
+ 0x6206119460289340L, 0x6380E75AE84E11B0L, 0x8BE772B6D6D0F16FL, 0x50929091D596CF6DL,
+ 0xE86795EC3E9EE0DFL, 0x7CF927482B581432L, 0xC86A3E14EEC26DB4L, 0x7119CDA78DACC0F6L,
+ 0xE40189CD100CB6EBL, 0x92ADBC3A028FDFF7L, 0xB2A017C2D2D3529CL, 0x200DABF8D05C8D6BL,
+ 0x34A78F9BA2F77737L, 0xE3B4719D8F231F01L, 0x45BE423C2F5BB7C1L, 0xF71E55FEFD88E55DL,
+ 0x6853032B59F3EE6EL, 0x65B3E9C4FF073AAAL, 0x772AC3399AE5EBECL, 0x87816E97F842A75BL,
+ 0x110E2DB2E0484A4BL, 0x331277CB3DD8DEDDL, 0xBD510CAC79EB9FA5L, 0x352179552A91F5C7L
+ },
+ {
+ 0x8AB0A96846E06A6DL, 0x43C7E80B4BF0B33AL, 0x08C9B3546B161EE5L, 0x39F1C235EBA990BEL,
+ 0xC1BEF2376606C7B2L, 0x2C209233614569AAL, 0xEB01523B6FC3289AL, 0x946953AB935ACEDDL,
+ 0x272838F63E13340EL, 0x8B0455ECA12BA052L, 0x77A1B2C4978FF8A2L, 0xA55122CA13E54086L,
+ 0x2276135862D3F1CDL, 0xDB8DDFDE08B76CFEL, 0x5D1E12C89E4A178AL, 0x0E56816B03969867L,
+ 0xEE5F79953303ED59L, 0xAFED748BAB78D71DL, 0x6D929F2DF93E53EEL, 0xF5D8A8F8BA798C2AL,
+ 0xF619B1698E39CF6BL, 0x95DDAF2F749104E2L, 0xEC2A9C80E0886427L, 0xCE5C8FD8825B95EAL,
+ 0xC4E0D9993AC60271L, 0x4699C3A5173076F9L, 0x3D1B151F50A29F42L, 0x9ED505EA2BC75946L,
+ 0x34665ACFDC7F4B98L, 0x61B1FB53292342F7L, 0xC721C0080E864130L, 0x8693CD1696FD7B74L,
+ 0x872731927136B14BL, 0xD3446C8A63A1721BL, 0x669A35E8A6680E4AL, 0xCAB658F239509A16L,
+ 0xA4E5DE4EF42E8AB9L, 0x37A7435EE83F08D9L, 0x134E6239E26C7F96L, 0x82791A3C2DF67488L,
+ 0x3F6EF00A8329163CL, 0x8E5A7E42FDEB6591L, 0x5CAAEE4C7981DDB5L, 0x19F234785AF1E80DL,
+ 0x255DDDE3ED98BD70L, 0x50898A32A99CCCACL, 0x28CA4519DA4E6656L, 0xAE59880F4CB31D22L,
+ 0x0D9798FA37D6DB26L, 0x32F968F0B4FFCD1AL, 0xA00F09644F258545L, 0xFA3AD5175E24DE72L,
+ 0xF46C547C5DB24615L, 0x713E80FBFF0F7E20L, 0x7843CF2B73D2AAFAL, 0xBD17EA36AEDF62B4L,
+ 0xFD111BACD16F92CFL, 0x4ABAA7DBC72D67E0L, 0xB3416B5DAD49FAD3L, 0xBCA316B24914A88BL,
+ 0x15D150068AECF914L, 0xE27C1DEBE31EFC40L, 0x4FE48C759BEDA223L, 0x7EDCFD141B522C78L,
+ 0x4E5070F17C26681CL, 0xE696CAC15815F3BCL, 0x35D2A64B3BB481A7L, 0x800CFF29FE7DFDF6L,
+ 0x1ED9FAC3D5BAA4B0L, 0x6C2663A91EF599D1L, 0x03C1199134404341L, 0xF7AD4DED69F20554L,
+ 0xCD9D9649B61BD6ABL, 0xC8C3BDE7EADB1368L, 0xD131899FB02AFB65L, 0x1D18E352E1FAE7F1L,
+ 0xDA39235AEF7CA6C1L, 0xA1BBF5E0A8EE4F7AL, 0x91377805CF9A0B1EL, 0x3138716180BF8E5BL,
+ 0xD9F83ACBDB3CE580L, 0x0275E515D38B897EL, 0x472D3F21F0FBBCC6L, 0x2D946EB7868EA395L,
+ 0xBA3C248D21942E09L, 0xE7223645BFDE3983L, 0xFF64FEB902E41BB1L, 0xC97741630D10D957L,
+ 0xC3CB1722B58D4ECCL, 0xA27AEC719CAE0C3BL, 0x99FECB51A48C15FBL, 0x1465AC826D27332BL,
+ 0xE1BD047AD75EBF01L, 0x79F733AF941960C5L, 0x672EC96C41A3C475L, 0xC27FEBA6524684F3L,
+ 0x64EFD0FD75E38734L, 0xED9E60040743AE18L, 0xFB8E2993B9EF144DL, 0x38453EB10C625A81L,
+ 0x6978480742355C12L, 0x48CF42CE14A6EE9EL, 0x1CAC1FD606312DCEL, 0x7B82D6BA4792E9BBL,
+ 0x9D141C7B1F871A07L, 0x5616B80DC11C4A2EL, 0xB849C198F21FA777L, 0x7CA91801C8D9A506L,
+ 0xB1348E487EC273ADL, 0x41B20D1E987B3A44L, 0x7460AB55A3CFBBE3L, 0x84E628034576F20AL,
+ 0x1B87D16D897A6173L, 0x0FE27DEFE45D5258L, 0x83CDE6B8CA3DBEB7L, 0x0C23647ED01D1119L,
+ 0x7A362A3EA0592384L, 0xB61F40F3F1893F10L, 0x75D457D1440471DCL, 0x4558DA34237035B8L,
+ 0xDCA6116587FC2043L, 0x8D9B67D3C9AB26D0L, 0x2B0B5C88EE0E2517L, 0x6FE77A382AB5DA90L,
+ 0x269CC472D9D8FE31L, 0x63C41E46FAA8CB89L, 0xB7ABBC771642F52FL, 0x7D1DE4852F126F39L,
+ 0xA8C6BA3024339BA0L, 0x600507D7CEE888C8L, 0x8FEE82C61A20AFAEL, 0x57A2448926D78011L,
+ 0xFCA5E72836A458F0L, 0x072BCEBB8F4B4CBDL, 0x497BBE4AF36D24A1L, 0x3CAFE99BB769557DL,
+ 0x12FA9EBD05A7B5A9L, 0xE8C04BAA5B836BDBL, 0x4273148FAC3B7905L, 0x908384812851C121L,
+ 0xE557D3506C55B0FDL, 0x72FF996ACB4F3D61L, 0x3EDA0C8E64E2DC03L, 0xF0868356E6B949E9L,
+ 0x04EAD72ABB0B0FFCL, 0x17A4B5135967706AL, 0xE3C8E16F04D5367FL, 0xF84F30028DAF570CL,
+ 0x1846C8FCBD3A2232L, 0x5B8120F7F6CA9108L, 0xD46FA231ECEA3EA6L, 0x334D947453340725L,
+ 0x58403966C28AD249L, 0xBED6F3A79A9F21F5L, 0x68CCB483A5FE962DL, 0xD085751B57E1315AL,
+ 0xFED0023DE52FD18EL, 0x4B0E5B5F20E6ADDFL, 0x1A332DE96EB1AB4CL, 0xA3CE10F57B65C604L,
+ 0x108F7BA8D62C3CD7L, 0xAB07A3A11073D8E1L, 0x6B0DAD1291BED56CL, 0xF2F366433532C097L,
+ 0x2E557726B2CEE0D4L, 0x0000000000000000L, 0xCB02A476DE9B5029L, 0xE4E32FD48B9E7AC2L,
+ 0x734B65EE2C84F75EL, 0x6E5386BCCD7E10AFL, 0x01B4FC84E7CBCA3FL, 0xCFE8735C65905FD5L,
+ 0x3613BFDA0FF4C2E6L, 0x113B872C31E7F6E8L, 0x2FE18BA255052AEBL, 0xE974B72EBC48A1E4L,
+ 0x0ABC5641B89D979BL, 0xB46AA5E62202B66EL, 0x44EC26B0C4BBFF87L, 0xA6903B5B27A503C7L,
+ 0x7F680190FC99E647L, 0x97A84A3AA71A8D9CL, 0xDD12EDE16037EA7CL, 0xC554251DDD0DC84EL,
+ 0x88C54C7D956BE313L, 0x4D91696048662B5DL, 0xB08072CC9909B992L, 0xB5DE5962C5C97C51L,
+ 0x81B803AD19B637C9L, 0xB2F597D94A8230ECL, 0x0B08AAC55F565DA4L, 0xF1327FD2017283D6L,
+ 0xAD98919E78F35E63L, 0x6AB9519676751F53L, 0x24E921670A53774FL, 0xB9FD3D1C15D46D48L,
+ 0x92F66194FBDA485FL, 0x5A35DC7311015B37L, 0xDED3F4705477A93DL, 0xC00A0EB381CD0D8DL,
+ 0xBB88D809C65FE436L, 0x16104997BEACBA55L, 0x21B70AC95693B28CL, 0x59F4C5E225411876L,
+ 0xD5DB5EB50B21F499L, 0x55D7A19CF55C096FL, 0xA97246B4C3F8519FL, 0x8552D487A2BD3835L,
+ 0x54635D181297C350L, 0x23C2EFDC85183BF2L, 0x9F61F96ECC0C9379L, 0x534893A39DDC8FEDL,
+ 0x5EDF0B59AA0A54CBL, 0xAC2C6D1A9F38945CL, 0xD7AEBBA0D8AA7DE7L, 0x2ABFA00C09C5EF28L,
+ 0xD84CC64F3CF72FBFL, 0x2003F64DB15878B3L, 0xA724C7DFC06EC9F8L, 0x069F323F68808682L,
+ 0xCC296ACD51D01C94L, 0x055E2BAE5CC0C5C3L, 0x6270E2C21D6301B6L, 0x3B842720382219C0L,
+ 0xD2F0900E846AB824L, 0x52FC6F277A1745D2L, 0xC6953C8CE94D8B0FL, 0xE009F8FE3095753EL,
+ 0x655B2C7992284D0BL, 0x984A37D54347DFC4L, 0xEAB5AEBF8808E2A5L, 0x9A3FD2C090CC56BAL,
+ 0x9CA0E0FFF84CD038L, 0x4C2595E4AFADE162L, 0xDF6708F4B3BC6302L, 0xBF620F237D54EBCAL,
+ 0x93429D101C118260L, 0x097D4FD08CDDD4DAL, 0x8C2F9B572E60ECEFL, 0x708A7C7F18C4B41FL,
+ 0x3A30DBA4DFE9D3FFL, 0x4006F19A7FB0F07BL, 0x5F6BF7DD4DC19EF4L, 0x1F6D064732716E8FL,
+ 0xF9FBCC866A649D33L, 0x308C8DE567744464L, 0x8971B0F972A0292CL, 0xD61A47243F61B7D8L,
+ 0xEFEB8511D4C82766L, 0x961CB6BE40D147A3L, 0xAAB35F25F7B812DEL, 0x76154E407044329DL,
+ 0x513D76B64E570693L, 0xF3479AC7D2F90AA8L, 0x9B8B2E4477079C85L, 0x297EB99D3D85AC69L
+ },
+ {
+ 0x7E37E62DFC7D40C3L, 0x776F25A4EE939E5BL, 0xE045C850DD8FB5ADL, 0x86ED5BA711FF1952L,
+ 0xE91D0BD9CF616B35L, 0x37E0AB256E408FFBL, 0x9607F6C031025A7AL, 0x0B02F5E116D23C9DL,
+ 0xF3D8486BFB50650CL, 0x621CFF27C40875F5L, 0x7D40CB71FA5FD34AL, 0x6DAA6616DAA29062L,
+ 0x9F5F354923EC84E2L, 0xEC847C3DC507C3B3L, 0x025A3668043CE205L, 0xA8BF9E6C4DAC0B19L,
+ 0xFA808BE2E9BEBB94L, 0xB5B99C5277C74FA3L, 0x78D9BC95F0397BCCL, 0xE332E50CDBAD2624L,
+ 0xC74FCE129332797EL, 0x1729ECEB2EA709ABL, 0xC2D6B9F69954D1F8L, 0x5D898CBFBAB8551AL,
+ 0x859A76FB17DD8ADBL, 0x1BE85886362F7FB5L, 0xF6413F8FF136CD8AL, 0xD3110FA5BBB7E35CL,
+ 0x0A2FEED514CC4D11L, 0xE83010EDCD7F1AB9L, 0xA1E75DE55F42D581L, 0xEEDE4A55C13B21B6L,
+ 0xF2F5535FF94E1480L, 0x0CC1B46D1888761EL, 0xBCE15FDB6529913BL, 0x2D25E8975A7181C2L,
+ 0x71817F1CE2D7A554L, 0x2E52C5CB5C53124BL, 0xF9F7A6BEEF9C281DL, 0x9E722E7D21F2F56EL,
+ 0xCE170D9B81DCA7E6L, 0x0E9B82051CB4941BL, 0x1E712F623C49D733L, 0x21E45CFA42F9F7DCL,
+ 0xCB8E7A7F8BBA0F60L, 0x8E98831A010FB646L, 0x474CCF0D8E895B23L, 0xA99285584FB27A95L,
+ 0x8CC2B57205335443L, 0x42D5B8E984EFF3A5L, 0x012D1B34021E718CL, 0x57A6626AAE74180BL,
+ 0xFF19FC06E3D81312L, 0x35BA9D4D6A7C6DFEL, 0xC9D44C178F86ED65L, 0x506523E6A02E5288L,
+ 0x03772D5C06229389L, 0x8B01F4FE0B691EC0L, 0xF8DABD8AED825991L, 0x4C4E3AEC985B67BEL,
+ 0xB10DF0827FBF96A9L, 0x6A69279AD4F8DAE1L, 0xE78689DCD3D5FF2EL, 0x812E1A2B1FA553D1L,
+ 0xFBAD90D6EBA0CA18L, 0x1AC543B234310E39L, 0x1604F7DF2CB97827L, 0xA6241C6951189F02L,
+ 0x753513CCEAAF7C5EL, 0x64F2A59FC84C4EFAL, 0x247D2B1E489F5F5AL, 0xDB64D718AB474C48L,
+ 0x79F4A7A1F2270A40L, 0x1573DA832A9BEBAEL, 0x3497867968621C72L, 0x514838D2A2302304L,
+ 0xF0AF6537FD72F685L, 0x1D06023E3A6B44BAL, 0x678588C3CE6EDD73L, 0x66A893F7CC70ACFFL,
+ 0xD4D24E29B5EDA9DFL, 0x3856321470EA6A6CL, 0x07C3418C0E5A4A83L, 0x2BCBB22F5635BACDL,
+ 0x04B46CD00878D90AL, 0x06EE5AB80C443B0FL, 0x3B211F4876C8F9E5L, 0x0958C38912EEDE98L,
+ 0xD14B39CDBF8B0159L, 0x397B292072F41BE0L, 0x87C0409313E168DEL, 0xAD26E98847CAA39FL,
+ 0x4E140C849C6785BBL, 0xD5FF551DB7F3D853L, 0xA0CA46D15D5CA40DL, 0xCD6020C787FE346FL,
+ 0x84B76DCF15C3FB57L, 0xDEFDA0FCA121E4CEL, 0x4B8D7B6096012D3DL, 0x9AC642AD298A2C64L,
+ 0x0875D8BD10F0AF14L, 0xB357C6EA7B8374ACL, 0x4D6321D89A451632L, 0xEDA96709C719B23FL,
+ 0xF76C24BBF328BC06L, 0xC662D526912C08F2L, 0x3CE25EC47892B366L, 0xB978283F6F4F39BDL,
+ 0xC08C8F9E9D6833FDL, 0x4F3917B09E79F437L, 0x593DE06FB2C08C10L, 0xD6887841B1D14BDAL,
+ 0x19B26EEE32139DB0L, 0xB494876675D93E2FL, 0x825937771987C058L, 0x90E9AC783D466175L,
+ 0xF1827E03FF6C8709L, 0x945DC0A8353EB87FL, 0x4516F9658AB5B926L, 0x3F9573987EB020EFL,
+ 0xB855330B6D514831L, 0x2AE6A91B542BCB41L, 0x6331E413C6160479L, 0x408F8E8180D311A0L,
+ 0xEFF35161C325503AL, 0xD06622F9BD9570D5L, 0x8876D9A20D4B8D49L, 0xA5533135573A0C8BL,
+ 0xE168D364DF91C421L, 0xF41B09E7F50A2F8FL, 0x12B09B0F24C1A12DL, 0xDA49CC2CA9593DC4L,
+ 0x1F5C34563E57A6BFL, 0x54D14F36A8568B82L, 0xAF7CDFE043F6419AL, 0xEA6A2685C943F8BCL,
+ 0xE5DCBFB4D7E91D2BL, 0xB27ADDDE799D0520L, 0x6B443CAED6E6AB6DL, 0x7BAE91C9F61BE845L,
+ 0x3EB868AC7CAE5163L, 0x11C7B65322E332A4L, 0xD23C1491B9A992D0L, 0x8FB5982E0311C7CAL,
+ 0x70AC6428E0C9D4D8L, 0x895BC2960F55FCC5L, 0x76423E90EC8DEFD7L, 0x6FF0507EDE9E7267L,
+ 0x3DCF45F07A8CC2EAL, 0x4AA06054941F5CB1L, 0x5810FB5BB0DEFD9CL, 0x5EFEA1E3BC9AC693L,
+ 0x6EDD4B4ADC8003EBL, 0x741808F8E8B10DD2L, 0x145EC1B728859A22L, 0x28BC9F7350172944L,
+ 0x270A06424EBDCCD3L, 0x972AEDF4331C2BF6L, 0x059977E40A66A886L, 0x2550302A4A812ED6L,
+ 0xDD8A8DA0A7037747L, 0xC515F87A970E9B7BL, 0x3023EAA9601AC578L, 0xB7E3AA3A73FBADA6L,
+ 0x0FB699311EAAE597L, 0x0000000000000000L, 0x310EF19D6204B4F4L, 0x229371A644DB6455L,
+ 0x0DECAF591A960792L, 0x5CA4978BB8A62496L, 0x1C2B190A38753536L, 0x41A295B582CD602CL,
+ 0x3279DCC16426277DL, 0xC1A194AA9F764271L, 0x139D803B26DFD0A1L, 0xAE51C4D441E83016L,
+ 0xD813FA44AD65DFC1L, 0xAC0BF2BC45D4D213L, 0x23BE6A9246C515D9L, 0x49D74D08923DCF38L,
+ 0x9D05032127D066E7L, 0x2F7FDEFF5E4D63C7L, 0xA47E2A0155247D07L, 0x99B16FF12FA8BFEDL,
+ 0x4661D4398C972AAFL, 0xDFD0BBC8A33F9542L, 0xDCA79694A51D06CBL, 0xB020EBB67DA1E725L,
+ 0xBA0F0563696DAA34L, 0xE4F1A480D5F76CA7L, 0xC438E34E9510EAF7L, 0x939E81243B64F2FCL,
+ 0x8DEFAE46072D25CFL, 0x2C08F3A3586FF04EL, 0xD7A56375B3CF3A56L, 0x20C947CE40E78650L,
+ 0x43F8A3DD86F18229L, 0x568B795EAC6A6987L, 0x8003011F1DBB225DL, 0xF53612D3F7145E03L,
+ 0x189F75DA300DEC3CL, 0x9570DB9C3720C9F3L, 0xBB221E576B73DBB8L, 0x72F65240E4F536DDL,
+ 0x443BE25188ABC8AAL, 0xE21FFE38D9B357A8L, 0xFD43CA6EE7E4F117L, 0xCAA3614B89A47EECL,
+ 0xFE34E732E1C6629EL, 0x83742C431B99B1D4L, 0xCF3A16AF83C2D66AL, 0xAAE5A8044990E91CL,
+ 0x26271D764CA3BD5FL, 0x91C4B74C3F5810F9L, 0x7C6DD045F841A2C6L, 0x7F1AFD19FE63314FL,
+ 0xC8F957238D989CE9L, 0xA709075D5306EE8EL, 0x55FC5402AA48FA0EL, 0x48FA563C9023BEB4L,
+ 0x65DFBEABCA523F76L, 0x6C877D22D8BCE1EEL, 0xCC4D3BF385E045E3L, 0xBEBB69B36115733EL,
+ 0x10EAAD6720FD4328L, 0xB6CEB10E71E5DC2AL, 0xBDCC44EF6737E0B7L, 0x523F158EA412B08DL,
+ 0x989C74C52DB6CE61L, 0x9BEB59992B945DE8L, 0x8A2CEFCA09776F4CL, 0xA3BD6B8D5B7E3784L,
+ 0xEB473DB1CB5D8930L, 0xC3FBA2C29B4AA074L, 0x9C28181525CE176BL, 0x683311F2D0C438E4L,
+ 0x5FD3BAD7BE84B71FL, 0xFC6ED15AE5FA809BL, 0x36CDB0116C5EFE77L, 0x29918447520958C8L,
+ 0xA29070B959604608L, 0x53120EBAA60CC101L, 0x3A0C047C74D68869L, 0x691E0AC6D2DA4968L,
+ 0x73DB4974E6EB4751L, 0x7A838AFDF40599C9L, 0x5A4ACD33B4E21F99L, 0x6046C94FC03497F0L,
+ 0xE6AB92E8D1CB8EA2L, 0x3354C7F5663856F1L, 0xD93EE170AF7BAE4DL, 0x616BD27BC22AE67CL,
+ 0x92B39A10397A8370L, 0xABC8B3304B8E9890L, 0xBF967287630B02B2L, 0x5B67D607B6FC6E15L
+ },
+ {
+ 0xD031C397CE553FE6L, 0x16BA5B01B006B525L, 0xA89BADE6296E70C8L, 0x6A1F525D77D3435BL,
+ 0x6E103570573DFA0BL, 0x660EFB2A17FC95ABL, 0x76327A9E97634BF6L, 0x4BAD9D6462458BF5L,
+ 0xF1830CAEDBC3F748L, 0xC5C8F542669131FFL, 0x95044A1CDC48B0CBL, 0x892962DF3CF8B866L,
+ 0xB0B9E208E930C135L, 0xA14FB3F0611A767CL, 0x8D2605F21C160136L, 0xD6B71922FECC549EL,
+ 0x37089438A5907D8BL, 0x0B5DA38E5803D49CL, 0x5A5BCC9CEA6F3CBCL, 0xEDAE246D3B73FFE5L,
+ 0xD2B87E0FDE22EDCEL, 0x5E54ABB1CA8185ECL, 0x1DE7F88FE80561B9L, 0xAD5E1A870135A08CL,
+ 0x2F2ADBD665CECC76L, 0x5780B5A782F58358L, 0x3EDC8A2EEDE47B3FL, 0xC9D95C3506BEE70FL,
+ 0x83BE111D6C4E05EEL, 0xA603B90959367410L, 0x103C81B4809FDE5DL, 0x2C69B6027D0C774AL,
+ 0x399080D7D5C87953L, 0x09D41E16487406B4L, 0xCDD63B1826505E5FL, 0xF99DC2F49B0298E8L,
+ 0x9CD0540A943CB67FL, 0xBCA84B7F891F17C5L, 0x723D1DB3B78DF2A6L, 0x78AA6E71E73B4F2EL,
+ 0x1433E699A071670DL, 0x84F21BE454620782L, 0x98DF3327B4D20F2FL, 0xF049DCE2D3769E5CL,
+ 0xDB6C60199656EB7AL, 0x648746B2078B4783L, 0x32CD23598DCBADCFL, 0x1EA4955BF0C7DA85L,
+ 0xE9A143401B9D46B5L, 0xFD92A5D9BBEC21B8L, 0xC8138C790E0B8E1BL, 0x2EE00B9A6D7BA562L,
+ 0xF85712B893B7F1FCL, 0xEB28FED80BEA949DL, 0x564A65EB8A40EA4CL, 0x6C9988E8474A2823L,
+ 0x4535898B121D8F2DL, 0xABD8C03231ACCBF4L, 0xBA2E91CAB9867CBDL, 0x7960BE3DEF8E263AL,
+ 0x0C11A977602FD6F0L, 0xCB50E1AD16C93527L, 0xEAE22E94035FFD89L, 0x2866D12F5DE2CE1AL,
+ 0xFF1B1841AB9BF390L, 0x9F9339DE8CFE0D43L, 0x964727C8C48A0BF7L, 0x524502C6AAAE531CL,
+ 0x9B9C5EF3AC10B413L, 0x4FA2FA4942AB32A5L, 0x3F165A62E551122BL, 0xC74148DA76E6E3D7L,
+ 0x924840E5E464B2A7L, 0xD372AE43D69784DAL, 0x233B72A105E11A86L, 0xA48A04914941A638L,
+ 0xB4B68525C9DE7865L, 0xDDEABAACA6CF8002L, 0x0A9773C250B6BD88L, 0xC284FFBB5EBD3393L,
+ 0x8BA0DF472C8F6A4EL, 0x2AEF6CB74D951C32L, 0x427983722A318D41L, 0x73F7CDFFBF389BB2L,
+ 0x074C0AF9382C026CL, 0x8A6A0F0B243A035AL, 0x6FDAE53C5F88931FL, 0xC68B98967E538AC3L,
+ 0x44FF59C71AA8E639L, 0xE2FCE0CE439E9229L, 0xA20CDE2479D8CD40L, 0x19E89FA2C8EBD8E9L,
+ 0xF446BBCFF398270CL, 0x43B3533E2284E455L, 0xD82F0DCD8E945046L, 0x51066F12B26CE820L,
+ 0xE73957AF6BC5426DL, 0x081ECE5A40C16FA0L, 0x3B193D4FC5BFAB7BL, 0x7FE66488DF174D42L,
+ 0x0E9814EF705804D8L, 0x8137AC857C39D7C6L, 0xB1733244E185A821L, 0x695C3F896F11F867L,
+ 0xF6CF0657E3EFF524L, 0x1AABF276D02963D5L, 0x2DA3664E75B91E5EL, 0x0289BD981077D228L,
+ 0x90C1FD7DF413608FL, 0x3C5537B6FD93A917L, 0xAA12107E3919A2E0L, 0x0686DAB530996B78L,
+ 0xDAA6B0559EE3826EL, 0xC34E2FF756085A87L, 0x6D5358A44FFF4137L, 0xFC587595B35948ACL,
+ 0x7CA5095CC7D5F67EL, 0xFB147F6C8B754AC0L, 0xBFEB26AB91DDACF9L, 0x6896EFC567A49173L,
+ 0xCA9A31E11E7C5C33L, 0xBBE44186B13315A9L, 0x0DDB793B689ABFE4L, 0x70B4A02BA7FA208EL,
+ 0xE47A3A7B7307F951L, 0x8CECD5BE14A36822L, 0xEEED49B923B144D9L, 0x17708B4DB8B3DC31L,
+ 0x6088219F2765FED3L, 0xB3FA8FDCF1F27A09L, 0x910B2D31FCA6099BL, 0x0F52C4A378ED6DCCL,
+ 0x50CCBF5EBAD98134L, 0x6BD582117F662A4FL, 0x94CE9A50D4FDD9DFL, 0x2B25BCFB45207526L,
+ 0x67C42B661F49FCBFL, 0x492420FC723259DDL, 0x03436DD418C2BB3CL, 0x1F6E4517F872B391L,
+ 0xA08563BC69AF1F68L, 0xD43EA4BAEEBB86B6L, 0x01CAD04C08B56914L, 0xAC94CACB0980C998L,
+ 0x54C3D8739A373864L, 0x26FEC5C02DBACAC2L, 0xDEA9D778BE0D3B3EL, 0x040F672D20EEB950L,
+ 0xE5B0EA377BB29045L, 0xF30AB136CBB42560L, 0x62019C0737122CFBL, 0xE86B930C13282FA1L,
+ 0xCC1CEB542EE5374BL, 0x538FD28AA21B3A08L, 0x1B61223AD89C0AC1L, 0x36C24474AD25149FL,
+ 0x7A23D3E9F74C9D06L, 0xBE21F6E79968C5EDL, 0xCF5F868036278C77L, 0xF705D61BEB5A9C30L,
+ 0x4D2B47D152DCE08DL, 0x5F9E7BFDC234ECF8L, 0x247778583DCD18EAL, 0x867BA67C4415D5AAL,
+ 0x4CE1979D5A698999L, 0x0000000000000000L, 0xEC64F42133C696F1L, 0xB57C5569C16B1171L,
+ 0xC1C7926F467F88AFL, 0x654D96FE0F3E2E97L, 0x15F936D5A8C40E19L, 0xB8A72C52A9F1AE95L,
+ 0xA9517DAA21DB19DCL, 0x58D27104FA18EE94L, 0x5918A148F2AD8780L, 0x5CDD1629DAF657C4L,
+ 0x8274C15164FB6CFAL, 0xD1FB13DBC6E056F2L, 0x7D6FD910CF609F6AL, 0xB63F38BDD9A9AA4DL,
+ 0x3D9FE7FAF526C003L, 0x74BBC706871499DEL, 0xDF630734B6B8522AL, 0x3AD3ED03CD0AC26FL,
+ 0xFADEAF2083C023D4L, 0xC00D42234ECAE1BBL, 0x8538CBA85CD76E96L, 0xC402250E6E2458EBL,
+ 0x47BC3413026A5D05L, 0xAFD7A71F114272A4L, 0x978DF784CC3F62E3L, 0xB96DFC1EA144C781L,
+ 0x21B2CF391596C8AEL, 0x318E4E8D950916F3L, 0xCE9556CC3E92E563L, 0x385A509BDD7D1047L,
+ 0x358129A0B5E7AFA3L, 0xE6F387E363702B79L, 0xE0755D5653E94001L, 0x7BE903A5FFF9F412L,
+ 0x12B53C2C90E80C75L, 0x3307F315857EC4DBL, 0x8FAFB86A0C61D31EL, 0xD9E5DD8186213952L,
+ 0x77F8AAD29FD622E2L, 0x25BDA814357871FEL, 0x7571174A8FA1F0CAL, 0x137FEC60985D6561L,
+ 0x30449EC19DBC7FE7L, 0xA540D4DD41F4CF2CL, 0xDC206AE0AE7AE916L, 0x5B911CD0E2DA55A8L,
+ 0xB2305F90F947131DL, 0x344BF9ECBD52C6B7L, 0x5D17C665D2433ED0L, 0x18224FEEC05EB1FDL,
+ 0x9E59E992844B6457L, 0x9A568EBFA4A5DD07L, 0xA3C60E68716DA454L, 0x7E2CB4C4D7A22456L,
+ 0x87B176304CA0BCBEL, 0x413AEEA632F3367DL, 0x9915E36BBC67663BL, 0x40F03EEA3A465F69L,
+ 0x1C2D28C3E0B008ADL, 0x4E682A054A1E5BB1L, 0x05C5B761285BD044L, 0xE1BF8D1A5B5C2915L,
+ 0xF2C0617AC3014C74L, 0xB7F5E8F1D11CC359L, 0x63CB4C4B3FA745EFL, 0x9D1A84469C89DF6BL,
+ 0xE33630824B2BFB3DL, 0xD5F474F6E60EEFA2L, 0xF58C6B83FB2D4E18L, 0x4676E45F0ADF3411L,
+ 0x20781F751D23A1BAL, 0xBD629B3381AA7ED1L, 0xAE1D775319F71BB0L, 0xFED1C80DA32E9A84L,
+ 0x5509083F92825170L, 0x29AC01635557A70EL, 0xA7C9694551831D04L, 0x8E65682604D4BA0AL,
+ 0x11F651F8882AB749L, 0xD77DC96EF6793D8AL, 0xEF2799F52B042DCDL, 0x48EEF0B07A8730C9L,
+ 0x22F1A2ED0D547392L, 0x6142F1D32FD097C7L, 0x4A674D286AF0E2E1L, 0x80FD7CC9748CBED2L,
+ 0x717E7067AF4F499AL, 0x938290A9ECD1DBB3L, 0x88E3B293344DD172L, 0x2734158C250FA3D6L
+ }
+ };
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_256Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_256Digest.java
new file mode 100644
index 00000000..2a9a32be
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_256Digest.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.util.Memoable;
+
+/**
+ * implementation of GOST R 34.11-2012 256-bit
+ */
+public final class GOST3411_2012_256Digest
+ extends GOST3411_2012Digest
+{
+ private final static byte[] IV = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+ };
+
+ public GOST3411_2012_256Digest()
+ {
+ super(IV);
+ }
+
+ public GOST3411_2012_256Digest(GOST3411_2012_256Digest other)
+ {
+ super(IV);
+ reset(other);
+ }
+
+ public String getAlgorithmName()
+ {
+ return "GOST3411-2012-256";
+ }
+
+ public int getDigestSize()
+ {
+ return 32;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] result = new byte[64];
+ super.doFinal(result, 0);
+
+ System.arraycopy(result, 32, out, outOff, 32);
+
+ return 32;
+ }
+
+ public Memoable copy()
+ {
+ return new GOST3411_2012_256Digest(this);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_512Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_512Digest.java
new file mode 100644
index 00000000..56ccc0f3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GOST3411_2012_512Digest.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.util.Memoable;
+
+/**
+ * implementation of GOST R 34.11-2012 512-bit
+ */
+public class GOST3411_2012_512Digest
+ extends GOST3411_2012Digest
+{
+ private final static byte[] IV = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ public GOST3411_2012_512Digest()
+ {
+ super(IV);
+ }
+
+ public GOST3411_2012_512Digest(GOST3411_2012_512Digest other)
+ {
+ super(IV);
+ reset(other);
+ }
+
+ public String getAlgorithmName()
+ {
+ return "GOST3411-2012-512";
+ }
+
+ public int getDigestSize()
+ {
+ return 64;
+ }
+
+ public Memoable copy()
+ {
+ return new GOST3411_2012_512Digest(this);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java
index 40194461..4a6be46b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java
@@ -242,11 +242,11 @@ public class KeccakDigest
if ((bitsInQueue % 8) != 0)
{
- throw new IllegalStateException("attempt to absorb with odd length queue.");
+ throw new IllegalStateException("attempt to absorb with odd length queue");
}
if (squeezing)
{
- throw new IllegalStateException("attempt to absorb while squeezing.");
+ throw new IllegalStateException("attempt to absorb while squeezing");
}
i = 0;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
index ff9cedf0..417c4bad 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
@@ -2,12 +2,14 @@ package org.bouncycastle.crypto.digests;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
* implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
*/
public class MD5Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 16;
@@ -24,6 +26,22 @@ public class MD5Digest
reset();
}
+ public MD5Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+
+ xOff = Pack.bigEndianToInt(encodedState, 32);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 36 + (i * 4));
+ }
+ }
+
/**
* Copy constructor. This will copy the state of the provided
* message digest.
@@ -320,4 +338,24 @@ public class MD5Digest
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[36 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(xOff, state, 32);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 36 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
index 450dda46..b81e7c0a 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -39,6 +39,11 @@ public class SHA1Digest
copyIn(t);
}
+ /**
+ * State constructor - create a digest initialised with the state of a previous one.
+ *
+ * @param encodedState the encoded state from the originating digest.
+ */
public SHA1Digest(byte[] encodedState)
{
super(encodedState);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
index 4f2b2842..c0fbd456 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -63,6 +63,11 @@ public class SHA224Digest
xOff = t.xOff;
}
+ /**
+ * State constructor - create a digest initialised with the state of a previous one.
+ *
+ * @param encodedState the encoded state from the originating digest.
+ */
public SHA224Digest(byte[] encodedState)
{
super(encodedState);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
index 600d2343..c6e3d283 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -63,6 +63,11 @@ public class SHA256Digest
xOff = t.xOff;
}
+ /**
+ * State constructor - create a digest initialised with the state of a previous one.
+ *
+ * @param encodedState the encoded state from the originating digest.
+ */
public SHA256Digest(byte[] encodedState)
{
super(encodedState);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
index fc9fa1e7..0c814b11 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -36,6 +36,11 @@ public class SHA384Digest
super(t);
}
+ /**
+ * State constructor - create a digest initialised with the state of a previous one.
+ *
+ * @param encodedState the encoded state from the originating digest.
+ */
public SHA384Digest(byte[] encodedState)
{
restoreState(encodedState);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
index 644bafad..dea3d88e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -36,6 +36,11 @@ public class SHA512Digest
super(t);
}
+ /**
+ * State constructor - create a digest initialised with the state of a previous one.
+ *
+ * @param encodedState the encoded state from the originating digest.
+ */
public SHA512Digest(byte[] encodedState)
{
restoreState(encodedState);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java
index 20dc641c..4266575d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java
@@ -50,12 +50,22 @@ public class SHAKEDigest
public int doFinal(byte[] out, int outOff, int outLen)
{
- absorb(new byte[]{ 0x0F }, 0, 4);
-
- squeeze(out, outOff, ((long)outLen) * 8);
+ int length = doOutput(out, outOff, outLen);
reset();
+ return length;
+ }
+
+ public int doOutput(byte[] out, int outOff, int outLen)
+ {
+ if (!squeezing)
+ {
+ absorb(new byte[]{0x0F}, 0, 4);
+ }
+
+ squeeze(out, outOff, ((long)outLen) * 8);
+
return outLen;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
index 17d8e3b0..471f5c22 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
@@ -4,10 +4,12 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.util.Arrays;
/**
* Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
@@ -25,7 +27,7 @@ public class OAEPEncoding
public OAEPEncoding(
AsymmetricBlockCipher cipher)
{
- this(cipher, new SHA1Digest(), null);
+ this(cipher, DigestFactory.createSHA1(), null);
}
public OAEPEncoding(
@@ -138,6 +140,11 @@ public class OAEPEncoding
int inLen)
throws InvalidCipherTextException
{
+ if (inLen > getInputBlockSize())
+ {
+ throw new DataLengthException("input data too long");
+ }
+
byte[] block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];
//
@@ -206,28 +213,17 @@ public class OAEPEncoding
throws InvalidCipherTextException
{
byte[] data = engine.processBlock(in, inOff, inLen);
- byte[] block;
+ byte[] block = new byte[engine.getOutputBlockSize()];
//
// as we may have zeros in our leading bytes for the block we produced
// on encryption, we need to make sure our decrypted block comes back
// the same size.
//
- if (data.length < engine.getOutputBlockSize())
- {
- block = new byte[engine.getOutputBlockSize()];
- System.arraycopy(data, 0, block, block.length - data.length, data.length);
- }
- else
- {
- block = data;
- }
+ System.arraycopy(data, 0, block, block.length - data.length, data.length);
- if (block.length < (2 * defHash.length) + 1)
- {
- throw new InvalidCipherTextException("data too short");
- }
+ boolean shortData = (block.length < (2 * defHash.length) + 1);
//
// unmask the seed.
@@ -264,31 +260,29 @@ public class OAEPEncoding
}
}
- if (defHashWrong)
- {
- throw new InvalidCipherTextException("data hash wrong");
- }
-
//
// find the data block
//
- int start;
+ int start = block.length;
- for (start = 2 * defHash.length; start != block.length; start++)
+ for (int index = 2 * defHash.length; index != block.length; index++)
{
- if (block[start] != 0)
+ if (block[index] != 0 & start == block.length)
{
- break;
+ start = index;
}
}
- if (start >= (block.length - 1) || block[start] != 1)
- {
- throw new InvalidCipherTextException("data start wrong " + start);
- }
+ boolean dataStartWrong = (start > (block.length - 1) | block[start] != 1);
start++;
+ if (defHashWrong | shortData | dataStartWrong)
+ {
+ Arrays.fill(block, (byte)0);
+ throw new InvalidCipherTextException("data wrong");
+ }
+
//
// extract the data block
//
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
index 46c7d435..e79557f4 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -9,6 +9,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Arrays;
/**
* this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
@@ -34,33 +35,35 @@ public class PKCS1Encoding
private static final int HEADER_LENGTH = 10;
- private SecureRandom random;
- private AsymmetricBlockCipher engine;
- private boolean forEncryption;
- private boolean forPrivateKey;
- private boolean useStrictLength;
- private int pLen = -1;
- private byte[] fallback = null;
+ private SecureRandom random;
+ private AsymmetricBlockCipher engine;
+ private boolean forEncryption;
+ private boolean forPrivateKey;
+ private boolean useStrictLength;
+ private int pLen = -1;
+ private byte[] fallback = null;
+ private byte[] blockBuffer;
/**
* Basic constructor.
+ *
* @param cipher
*/
public PKCS1Encoding(
- AsymmetricBlockCipher cipher)
+ AsymmetricBlockCipher cipher)
{
this.engine = cipher;
this.useStrictLength = useStrict();
- }
+ }
/**
* Constructor for decryption with a fixed plaintext length.
- *
+ *
* @param cipher The cipher to use for cryptographic operation.
- * @param pLen Length of the expected plaintext.
+ * @param pLen Length of the expected plaintext.
*/
public PKCS1Encoding(
- AsymmetricBlockCipher cipher,
+ AsymmetricBlockCipher cipher,
int pLen)
{
this.engine = cipher;
@@ -68,27 +71,24 @@ public class PKCS1Encoding
this.pLen = pLen;
}
- /**
- * Constructor for decryption with a fixed plaintext length and a fallback
- * value that is returned, if the padding is incorrect.
- *
- * @param cipher
- * The cipher to use for cryptographic operation.
- * @param fallback
- * The fallback value, we don't do an arraycopy here.
- */
- public PKCS1Encoding(
- AsymmetricBlockCipher cipher,
+ /**
+ * Constructor for decryption with a fixed plaintext length and a fallback
+ * value that is returned, if the padding is incorrect.
+ *
+ * @param cipher The cipher to use for cryptographic operation.
+ * @param fallback The fallback value, we don't do an arraycopy here.
+ */
+ public PKCS1Encoding(
+ AsymmetricBlockCipher cipher,
byte[] fallback)
{
- this.engine = cipher;
- this.useStrictLength = useStrict();
- this.fallback = fallback;
- this.pLen = fallback.length;
+ this.engine = cipher;
+ this.useStrictLength = useStrict();
+ this.fallback = fallback;
+ this.pLen = fallback.length;
}
-
-
+
//
// for J2ME compatibility
//
@@ -124,14 +124,14 @@ public class PKCS1Encoding
}
public void init(
- boolean forEncryption,
- CipherParameters param)
+ boolean forEncryption,
+ CipherParameters param)
{
- AsymmetricKeyParameter kParam;
+ AsymmetricKeyParameter kParam;
if (param instanceof ParametersWithRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
this.random = rParam.getRandom();
kParam = (AsymmetricKeyParameter)rParam.getParameters();
@@ -149,11 +149,17 @@ public class PKCS1Encoding
this.forPrivateKey = kParam.isPrivate();
this.forEncryption = forEncryption;
+ this.blockBuffer = new byte[engine.getOutputBlockSize()];
+
+ if (pLen > 0 && fallback == null && random == null)
+ {
+ throw new IllegalArgumentException("encoder requires random");
+ }
}
public int getInputBlockSize()
{
- int baseBlockSize = engine.getInputBlockSize();
+ int baseBlockSize = engine.getInputBlockSize();
if (forEncryption)
{
@@ -167,7 +173,7 @@ public class PKCS1Encoding
public int getOutputBlockSize()
{
- int baseBlockSize = engine.getOutputBlockSize();
+ int baseBlockSize = engine.getOutputBlockSize();
if (forEncryption)
{
@@ -180,9 +186,9 @@ public class PKCS1Encoding
}
public byte[] processBlock(
- byte[] in,
- int inOff,
- int inLen)
+ byte[] in,
+ int inOff,
+ int inLen)
throws InvalidCipherTextException
{
if (forEncryption)
@@ -196,17 +202,17 @@ public class PKCS1Encoding
}
private byte[] encodeBlock(
- byte[] in,
- int inOff,
- int inLen)
+ byte[] in,
+ int inOff,
+ int inLen)
throws InvalidCipherTextException
{
if (inLen > getInputBlockSize())
{
throw new IllegalArgumentException("input data too large");
}
-
- byte[] block = new byte[engine.getInputBlockSize()];
+
+ byte[] block = new byte[engine.getInputBlockSize()];
if (forPrivateKey)
{
@@ -241,62 +247,63 @@ public class PKCS1Encoding
return engine.processBlock(block, 0, block.length);
}
-
+
/**
* Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
* for encryption.
- *
+ *
* @param encoded The Plaintext.
- * @param pLen Expected length of the plaintext.
+ * @param pLen Expected length of the plaintext.
* @return Either 0, if the encoding is correct, or -1, if it is incorrect.
*/
- private static int checkPkcs1Encoding(byte[] encoded, int pLen) {
- int correct = 0;
- /*
+ private static int checkPkcs1Encoding(byte[] encoded, int pLen)
+ {
+ int correct = 0;
+ /*
* Check if the first two bytes are 0 2
*/
- correct |= (encoded[0] ^ 2);
+ correct |= (encoded[0] ^ 2);
/*
* Now the padding check, check for no 0 byte in the padding
*/
- int plen = encoded.length - (
- pLen /* Lenght of the PMS */
- + 1 /* Final 0-byte before PMS */
- );
-
- for (int i = 1; i < plen; i++) {
- int tmp = encoded[i];
- tmp |= tmp >> 1;
- tmp |= tmp >> 2;
- tmp |= tmp >> 4;
- correct |= (tmp & 1) - 1;
- }
+ int plen = encoded.length - (
+ pLen /* Lenght of the PMS */
+ + 1 /* Final 0-byte before PMS */
+ );
+
+ for (int i = 1; i < plen; i++)
+ {
+ int tmp = encoded[i];
+ tmp |= tmp >> 1;
+ tmp |= tmp >> 2;
+ tmp |= tmp >> 4;
+ correct |= (tmp & 1) - 1;
+ }
/*
* Make sure the padding ends with a 0 byte.
*/
- correct |= encoded[encoded.length - (pLen +1)];
+ correct |= encoded[encoded.length - (pLen + 1)];
/*
* Return 0 or 1, depending on the result.
*/
- correct |= correct >> 1;
- correct |= correct >> 2;
- correct |= correct >> 4;
- return ~((correct & 1) - 1);
- }
-
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ return ~((correct & 1) - 1);
+ }
+
/**
* Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
- *
- * @param in The encrypted block.
+ *
+ * @param in The encrypted block.
* @param inOff Offset in the encrypted block.
* @param inLen Length of the encrypted block.
- * //@param pLen Length of the desired output.
+ * //@param pLen Length of the desired output.
* @return The plaintext without padding, or a random value if the padding was incorrect.
- *
* @throws InvalidCipherTextException
*/
private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen)
@@ -308,7 +315,7 @@ public class PKCS1Encoding
}
byte[] block = engine.processBlock(in, inOff, inLen);
- byte[] random = null;
+ byte[] random;
if (this.fallback == null)
{
random = new byte[this.pLen];
@@ -319,30 +326,12 @@ public class PKCS1Encoding
random = fallback;
}
- /*
- * TODO: This is a potential dangerous side channel. However, you can
- * fix this by changing the RSA engine in a way, that it will always
- * return blocks of the same length and prepend them with 0 bytes if
- * needed.
- */
- if (block.length < getOutputBlockSize())
- {
- throw new InvalidCipherTextException("block truncated");
- }
-
- /*
- * TODO: Potential side channel. Fix it by making the engine always
- * return blocks of the correct length.
- */
- if (useStrictLength && block.length != engine.getOutputBlockSize())
- {
- throw new InvalidCipherTextException("block incorrect size");
- }
+ byte[] data = (useStrictLength & (block.length != engine.getOutputBlockSize())) ? blockBuffer : block;
/*
* Check the padding.
*/
- int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen);
+ int correct = PKCS1Encoding.checkPkcs1Encoding(data, this.pLen);
/*
* Now, to a constant time constant memory copy of the decrypted value
@@ -351,89 +340,106 @@ public class PKCS1Encoding
byte[] result = new byte[this.pLen];
for (int i = 0; i < this.pLen; i++)
{
- result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct));
+ result[i] = (byte)((data[i + (data.length - pLen)] & (~correct)) | (random[i] & correct));
}
+ Arrays.fill(data, (byte)0);
+
return result;
}
/**
- * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
+ * @throws InvalidCipherTextException if the decrypted block is not in PKCS1 format.
*/
private byte[] decodeBlock(
- byte[] in,
- int inOff,
- int inLen)
+ byte[] in,
+ int inOff,
+ int inLen)
throws InvalidCipherTextException
{
/*
* If the length of the expected plaintext is known, we use a constant-time decryption.
* If the decryption fails, we return a random value.
*/
- if (this.pLen != -1)
+ if (this.pLen != -1)
{
- return this.decodeBlockOrRandom(in, inOff, inLen);
- }
-
+ return this.decodeBlockOrRandom(in, inOff, inLen);
+ }
+
byte[] block = engine.processBlock(in, inOff, inLen);
+ boolean incorrectLength = (useStrictLength & (block.length != engine.getOutputBlockSize()));
+ byte[] data;
if (block.length < getOutputBlockSize())
{
- throw new InvalidCipherTextException("block truncated");
+ data = blockBuffer;
+ }
+ else
+ {
+ data = block;
}
- byte type = block[0];
+ byte type = data[0];
+ boolean badType;
if (forPrivateKey)
{
- if (type != 2)
- {
- throw new InvalidCipherTextException("unknown block type");
- }
+ badType = (type != 2);
}
else
{
- if (type != 1)
- {
- throw new InvalidCipherTextException("unknown block type");
- }
+ badType = (type != 1);
}
- if (useStrictLength && block.length != engine.getOutputBlockSize())
- {
- throw new InvalidCipherTextException("block incorrect size");
- }
-
//
// find and extract the message block.
//
- int start;
-
- for (start = 1; start != block.length; start++)
- {
- byte pad = block[start];
-
- if (pad == 0)
- {
- break;
- }
- if (type == 1 && pad != (byte)0xff)
- {
- throw new InvalidCipherTextException("block padding incorrect");
- }
- }
+ int start = findStart(type, data);
start++; // data should start at the next byte
- if (start > block.length || start < HEADER_LENGTH)
+ if (badType | start < HEADER_LENGTH)
+ {
+ Arrays.fill(data, (byte)0);
+ throw new InvalidCipherTextException("block incorrect");
+ }
+
+ // if we get this far, it's likely to be a genuine encoding error
+ if (incorrectLength)
{
- throw new InvalidCipherTextException("no data in block");
+ Arrays.fill(data, (byte)0);
+ throw new InvalidCipherTextException("block incorrect size");
}
- byte[] result = new byte[block.length - start];
+ byte[] result = new byte[data.length - start];
- System.arraycopy(block, start, result, 0, result.length);
+ System.arraycopy(data, start, result, 0, result.length);
return result;
}
+
+ private int findStart(byte type, byte[] block)
+ throws InvalidCipherTextException
+ {
+ int start = -1;
+ boolean padErr = false;
+
+ for (int i = 1; i != block.length; i++)
+ {
+ byte pad = block[i];
+
+ if (pad == 0 & start < 0)
+ {
+ start = i;
+ }
+ padErr |= (type == 1 & start < 0 & pad != (byte)0xff);
+ }
+
+ if (padErr)
+ {
+ return -1;
+ }
+
+ return start;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
index 924dff35..021b0f7d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
@@ -5,6 +5,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
/**
@@ -415,6 +416,8 @@ private static final int[] Tinv0 =
private int C0, C1, C2, C3;
private boolean forEncryption;
+ private byte[] s;
+
private static final int BLOCK_SIZE = 16;
/**
@@ -440,6 +443,14 @@ private static final int[] Tinv0 =
{
WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
this.forEncryption = forEncryption;
+ if (forEncryption)
+ {
+ s = Arrays.clone(S);
+ }
+ else
+ {
+ s = Arrays.clone(Si);
+ }
return;
}
@@ -578,10 +589,10 @@ private static final int[] Tinv0 =
// the final round's table is a simple function of S so we don't use a whole other four tables for it
- this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
- this.C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
- this.C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
- this.C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+ this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[r][0];
+ this.C1 = (s[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[r][1];
+ this.C2 = (s[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+ this.C3 = (s[r3&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
}
private void decryptBlock(int[][] KW)
@@ -610,9 +621,9 @@ private static final int[] Tinv0 =
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
- this.C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
- this.C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
- this.C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
- this.C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+ this.C0 = (Si[r0&255]&255) ^ ((s[(r3>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+ this.C1 = (s[r1&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (s[(r2>>24)&255]<<24) ^ KW[0][1];
+ this.C2 = (s[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[0][2];
+ this.C3 = (Si[r3&255]&255) ^ ((s[(r2>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[0][3];
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
index 11e1bce8..abb8ba8c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
@@ -26,9 +26,11 @@ import org.bouncycastle.util.Pack;
* the contents of the first
*
* The slowest version uses no static tables at all and computes the values in each round
+ * </p>
* <p>
- * This file contains the fast version with 8Kbytes of static tables for round precomputation
- *
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation.
+ * </p>
+ * @deprecated unfortunately this class is has a few side channel issues. In an environment where encryption/decryption may be closely observed it should not be used.
*/
public class AESFastEngine
implements BlockCipher
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java
new file mode 100644
index 00000000..c795c857
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaCha7539Engine.java
@@ -0,0 +1,120 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.util.Pack;
+
+/**
+ * Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+ */
+public class ChaCha7539Engine extends Salsa20Engine
+{
+ /**
+ * Creates a 20 rounds ChaCha engine.
+ */
+ public ChaCha7539Engine()
+ {
+ super();
+ }
+
+ public String getAlgorithmName()
+ {
+ return "ChaCha7539-" + rounds;
+ }
+
+ protected int getNonceSize()
+ {
+ return 12;
+ }
+
+ protected void advanceCounter(long diff)
+ {
+ int hi = (int)(diff >>> 32);
+ int lo = (int)diff;
+
+ if (hi > 0)
+ {
+ throw new IllegalStateException("attempt to increase counter past 2^32.");
+ }
+
+ int oldState = engineState[12];
+
+ engineState[12] += lo;
+
+ if (oldState != 0 && engineState[12] < oldState)
+ {
+ throw new IllegalStateException("attempt to increase counter past 2^32.");
+ }
+ }
+
+ protected void advanceCounter()
+ {
+ if (++engineState[12] == 0)
+ {
+ throw new IllegalStateException("attempt to increase counter past 2^32.");
+ }
+ }
+
+ protected void retreatCounter(long diff)
+ {
+ int hi = (int)(diff >>> 32);
+ int lo = (int)diff;
+
+ if (hi != 0)
+ {
+ throw new IllegalStateException("attempt to reduce counter past zero.");
+ }
+
+ if ((engineState[12] & 0xffffffffL) >= (lo & 0xffffffffL))
+ {
+ engineState[12] -= lo;
+ }
+ else
+ {
+ throw new IllegalStateException("attempt to reduce counter past zero.");
+ }
+ }
+
+ protected void retreatCounter()
+ {
+ if (engineState[12] == 0)
+ {
+ throw new IllegalStateException("attempt to reduce counter past zero.");
+ }
+
+ --engineState[12];
+ }
+
+ protected long getCounter()
+ {
+ return engineState[12] & 0xffffffffL;
+ }
+
+ protected void resetCounter()
+ {
+ engineState[12] = 0;
+ }
+
+ protected void setKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if (keyBytes != null)
+ {
+ if (keyBytes.length != 32)
+ {
+ throw new IllegalArgumentException(getAlgorithmName() + " requires 256 bit key");
+ }
+
+ packTauOrSigma(keyBytes.length, engineState, 0);
+
+ // Key
+ Pack.littleEndianToInt(keyBytes, 0, engineState, 4, 8);
+ }
+
+ // IV
+ Pack.littleEndianToInt(ivBytes, 0, engineState, 13, 3);
+ }
+
+ protected void generateKeyStream(byte[] output)
+ {
+ ChaChaEngine.chachaCore(rounds, engineState, x);
+ Pack.intToLittleEndian(x, output, 0);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java
index d4c43897..58a2171c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java
@@ -124,39 +124,15 @@ public class ChaChaEngine extends Salsa20Engine
throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key");
}
- // Key
- engineState[4] = Pack.littleEndianToInt(keyBytes, 0);
- engineState[5] = Pack.littleEndianToInt(keyBytes, 4);
- engineState[6] = Pack.littleEndianToInt(keyBytes, 8);
- engineState[7] = Pack.littleEndianToInt(keyBytes, 12);
+ packTauOrSigma(keyBytes.length, engineState, 0);
- byte[] constants;
- int offset;
- if (keyBytes.length == 32)
- {
- constants = sigma;
- offset = 16;
- }
- else
- {
- constants = tau;
- offset = 0;
- }
-
- engineState[8] = Pack.littleEndianToInt(keyBytes, offset);
- engineState[9] = Pack.littleEndianToInt(keyBytes, offset + 4);
- engineState[10] = Pack.littleEndianToInt(keyBytes, offset + 8);
- engineState[11] = Pack.littleEndianToInt(keyBytes, offset + 12);
-
- engineState[0] = Pack.littleEndianToInt(constants, 0);
- engineState[1] = Pack.littleEndianToInt(constants, 4);
- engineState[2] = Pack.littleEndianToInt(constants, 8);
- engineState[3] = Pack.littleEndianToInt(constants, 12);
+ // Key
+ Pack.littleEndianToInt(keyBytes, 0, engineState, 4, 4);
+ Pack.littleEndianToInt(keyBytes, keyBytes.length - 16, engineState, 8, 4);
}
// IV
- engineState[14] = Pack.littleEndianToInt(ivBytes, 0);
- engineState[15] = Pack.littleEndianToInt(ivBytes, 4);
+ Pack.littleEndianToInt(ivBytes, 0, engineState, 14, 2);
}
protected void generateKeyStream(byte[] output)
@@ -166,7 +142,7 @@ public class ChaChaEngine extends Salsa20Engine
}
/**
- * ChacCha function
+ * ChaCha function
*
* @param input input data
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
index 76e3bb8a..d160a01c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -6,11 +6,11 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.util.Arrays;
/**
@@ -51,7 +51,7 @@ public class DESedeWrapEngine
//
// checksum digest
//
- Digest sha1 = new SHA1Digest();
+ Digest sha1 = DigestFactory.createSHA1();
byte[] digest = new byte[20];
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
index 7c320119..740379ba 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
@@ -67,8 +67,8 @@ public class IESEngine
/**
- * set up for use in conjunction with a block cipher to handle the
- * message.
+ * Set up for use in conjunction with a block cipher to handle the
+ * message.It is <b>strongly</b> recommended that the cipher is not in ECB mode.
*
* @param agree the key agreement used as the basis for the encryption
* @param kdf the key derivation function used for byte generation
@@ -269,8 +269,8 @@ public class IESEngine
int inLen)
throws InvalidCipherTextException
{
- byte[] M = null, K = null, K1 = null, K2 = null;
- int len;
+ byte[] M, K, K1, K2;
+ int len = 0;
// Ensure that the length of the input is greater than the MAC in bytes
if (inLen < V.length + mac.getMacSize())
@@ -278,6 +278,7 @@ public class IESEngine
throw new InvalidCipherTextException("Length of input must be greater than the MAC and V combined");
}
+ // note order is important: set up keys, do simple encryptions, check mac, do final encryption.
if (cipher == null)
{
// Streaming mode.
@@ -298,14 +299,13 @@ public class IESEngine
System.arraycopy(K, K1.length, K2, 0, K2.length);
}
+ // process the message
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
{
@@ -325,15 +325,15 @@ public class IESEngine
}
else
{
- cipher.init(false, new KeyParameter(K1));
+ cipher.init(false, new KeyParameter(K1));
}
M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())];
+
+ // do initial processing
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 = null;
@@ -362,11 +362,19 @@ public class IESEngine
if (!Arrays.constantTimeAreEqual(T1, T2))
{
- throw new InvalidCipherTextException("Invalid MAC.");
+ throw new InvalidCipherTextException("invalid MAC");
+ }
+
+ if (cipher == null)
+ {
+ return M;
}
+ else
+ {
+ len += cipher.doFinal(M, len);
- // Output the message.
- return Arrays.copyOfRange(M, 0, len);
+ return Arrays.copyOfRange(M, 0, len);
+ }
}
@@ -400,6 +408,10 @@ public class IESEngine
{
throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
}
+ catch (IllegalArgumentException 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);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java
index 4488f744..27b1c3c2 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2WrapEngine.java
@@ -6,10 +6,10 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.util.Arrays;
/**
@@ -43,7 +43,7 @@ public class RC2WrapEngine
//
// checksum digest
//
- Digest sha1 = new SHA1Digest();
+ Digest sha1 = DigestFactory.createSHA1();
byte[] digest = new byte[20];
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java
index 83e22ca0..94d15b74 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC5649WrapEngine.java
@@ -48,6 +48,7 @@ public class RFC5649WrapEngine
if (param instanceof KeyParameter)
{
this.param = (KeyParameter)param;
+ this.preIV = highOrderIV;
}
else if (param instanceof ParametersWithIV)
{
@@ -192,7 +193,6 @@ public class RFC5649WrapEngine
System.arraycopy(extractedAIV, 0, extractedHighOrderAIV, 0, extractedHighOrderAIV.length);
System.arraycopy(extractedAIV, extractedHighOrderAIV.length, mliBytes, 0, mliBytes.length);
int mli = Pack.bigEndianToInt(mliBytes, 0);
-
// Even if a check fails we still continue and check everything
// else in order to avoid certain timing based side-channel attacks.
boolean isValid = true;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
index 13aada9e..f25a25ef 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
@@ -21,6 +21,18 @@ public class Salsa20Engine
/** Constants */
private final static int STATE_SIZE = 16; // 16, 32 bit ints = 64 bytes
+ private final static int[] TAU_SIGMA = Pack.littleEndianToInt(Strings.toByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
+
+ protected void packTauOrSigma(int keyLength, int[] state, int stateOffset)
+ {
+ int tsOff = (keyLength - 16) / 4;
+ state[stateOffset ] = TAU_SIGMA[tsOff ];
+ state[stateOffset + 1] = TAU_SIGMA[tsOff + 1];
+ state[stateOffset + 2] = TAU_SIGMA[tsOff + 2];
+ state[stateOffset + 3] = TAU_SIGMA[tsOff + 3];
+ }
+
+ /** @deprecated */
protected final static byte[]
sigma = Strings.toByteArray("expand 32-byte k"),
tau = Strings.toByteArray("expand 16-byte k");
@@ -365,39 +377,19 @@ public class Salsa20Engine
throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key");
}
- // Key
- engineState[1] = Pack.littleEndianToInt(keyBytes, 0);
- engineState[2] = Pack.littleEndianToInt(keyBytes, 4);
- engineState[3] = Pack.littleEndianToInt(keyBytes, 8);
- engineState[4] = Pack.littleEndianToInt(keyBytes, 12);
-
- byte[] constants;
- int offset;
- if (keyBytes.length == 32)
- {
- constants = sigma;
- offset = 16;
- }
- else
- {
- constants = tau;
- offset = 0;
- }
+ int tsOff = (keyBytes.length - 16) / 4;
+ engineState[0 ] = TAU_SIGMA[tsOff ];
+ engineState[5 ] = TAU_SIGMA[tsOff + 1];
+ engineState[10] = TAU_SIGMA[tsOff + 2];
+ engineState[15] = TAU_SIGMA[tsOff + 3];
- engineState[11] = Pack.littleEndianToInt(keyBytes, offset);
- engineState[12] = Pack.littleEndianToInt(keyBytes, offset + 4);
- engineState[13] = Pack.littleEndianToInt(keyBytes, offset + 8);
- engineState[14] = Pack.littleEndianToInt(keyBytes, offset + 12);
-
- engineState[0 ] = Pack.littleEndianToInt(constants, 0);
- engineState[5 ] = Pack.littleEndianToInt(constants, 4);
- engineState[10] = Pack.littleEndianToInt(constants, 8);
- engineState[15] = Pack.littleEndianToInt(constants, 12);
+ // Key
+ Pack.littleEndianToInt(keyBytes, 0, engineState, 1, 4);
+ Pack.littleEndianToInt(keyBytes, keyBytes.length - 16, engineState, 11, 4);
}
// IV
- engineState[6] = Pack.littleEndianToInt(ivBytes, 0);
- engineState[7] = Pack.littleEndianToInt(ivBytes, 4);
+ Pack.littleEndianToInt(ivBytes, 0, engineState, 6, 2);
}
protected void generateKeyStream(byte[] output)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java
index 45cc478e..4b0a5edd 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java
@@ -40,8 +40,7 @@ public class XSalsa20Engine extends Salsa20Engine
super.setKey(keyBytes, ivBytes);
// Pack next 64 bits of IV into engine state instead of counter
- engineState[8] = Pack.littleEndianToInt(ivBytes, 8);
- engineState[9] = Pack.littleEndianToInt(ivBytes, 12);
+ Pack.littleEndianToInt(ivBytes, 8, engineState, 8, 2);
// Process engine state to generate Salsa20 key
int[] hsalsa20Out = new int[engineState.length];
@@ -59,7 +58,6 @@ public class XSalsa20Engine extends Salsa20Engine
engineState[14] = hsalsa20Out[9] - engineState[9];
// Last 64 bits of input IV
- engineState[6] = Pack.littleEndianToInt(ivBytes, 16);
- engineState[7] = Pack.littleEndianToInt(ivBytes, 20);
+ Pack.littleEndianToInt(ivBytes, 16, engineState, 6, 2);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/examples/DESExample.java b/bcprov/src/main/java/org/bouncycastle/crypto/examples/DESExample.java
index 90a21def..48412116 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/examples/DESExample.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/examples/DESExample.java
@@ -271,7 +271,7 @@ public class DESExample extends Object
}
catch (IOException closing)
{
-
+ System.err.println("exception closing resources: " + closing.getMessage());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/BCrypt.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/BCrypt.java
index 8ad9c46b..5dac6a1b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/BCrypt.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/BCrypt.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.generators;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
/**
* Core of password hashing scheme Bcrypt,
@@ -388,22 +389,6 @@ public final class BCrypt
}
- private int BytesTo32bits(byte[] b, int i)
- {
- return ((b[i] & 0xff) << 24) |
- ((b[i + 1] & 0xff) << 16) |
- ((b[i + 2] & 0xff) << 8) |
- ((b[i + 3] & 0xff));
- }
-
- private void Bits32ToBytes(int in, byte[] b, int offset)
- {
- b[offset + 3] = (byte)in;
- b[offset + 2] = (byte)(in >> 8);
- b[offset + 1] = (byte)(in >> 16);
- b[offset] = (byte)(in >> 24);
- }
-
/*
* XOR P with key cyclic.
* This is the first part of ExpandKey function
@@ -464,10 +449,7 @@ public final class BCrypt
}
}
byte[] result = new byte[24]; // holds 192 bit key
- for (int i = 0; i < text.length; i++)
- {
- Bits32ToBytes(text[i], result, i * 4);
- }
+ Pack.intToBigEndian(text, result, 0);
Arrays.fill(text, 0);
Arrays.fill(P, 0);
Arrays.fill(S, 0);
@@ -564,10 +546,7 @@ public final class BCrypt
initState();
int[] salt32Bit = new int[4]; // holds 16 byte salt
- salt32Bit[0] = BytesTo32bits(salt, 0);
- salt32Bit[1] = BytesTo32bits(salt, 4);
- salt32Bit[2] = BytesTo32bits(salt, 8);
- salt32Bit[3] = BytesTo32bits(salt, 12);
+ Pack.bigEndianToInt(salt, 0, salt32Bit);
int[] salt32Bit2 = new int[salt.length]; // swapped values
salt32Bit2[0] = salt32Bit[2];
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
index b284a931..b5a20808 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
@@ -54,7 +54,7 @@ public class BaseKDFBytesGenerator
}
else
{
- throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ throw new IllegalArgumentException("KDF parameters required for generator");
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index 054b7a8b..6411a1fb 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -8,6 +8,7 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAValidationParameters;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
@@ -31,7 +32,7 @@ public class DSAParametersGenerator
public DSAParametersGenerator()
{
- this(new SHA1Digest());
+ this(DigestFactory.createSHA1());
}
public DSAParametersGenerator(Digest digest)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenBSDBCrypt.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenBSDBCrypt.java
index b5f133fe..a546c5d5 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenBSDBCrypt.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenBSDBCrypt.java
@@ -173,7 +173,7 @@ public class OpenBSDBCrypt
}
catch (NumberFormatException nfe)
{
- throw new IllegalArgumentException("Invalid cost factor:"
+ throw new IllegalArgumentException("Invalid cost factor: "
+ bcryptString.substring(4, 6));
}
if (cost < 4 || cost > 31)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
index 8a4d28ab..dd8e5892 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -3,9 +3,9 @@ package org.bouncycastle.crypto.generators;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.util.DigestFactory;
/**
* Generator for PBE derived keys and ivs as usd by OpenSSL.
@@ -17,7 +17,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
public class OpenSSLPBEParametersGenerator
extends PBEParametersGenerator
{
- private Digest digest = new MD5Digest();
+ private Digest digest = DigestFactory.createMD5();
/**
* Construct a OpenSSL Parameters generator.
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
index 3fe8b9c1..94e70e7e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -4,10 +4,10 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.util.Arrays;
/**
@@ -29,7 +29,7 @@ public class PKCS5S2ParametersGenerator
*/
public PKCS5S2ParametersGenerator()
{
- this(new SHA1Digest());
+ this(DigestFactory.createSHA1());
}
public PKCS5S2ParametersGenerator(Digest digest)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java
index 59eee39e..ea4e7744 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java
@@ -68,17 +68,17 @@ public class Poly1305KeyGenerator
/*
* r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
*/
- key[19] &= R_MASK_HIGH_4;
- key[23] &= R_MASK_HIGH_4;
- key[27] &= R_MASK_HIGH_4;
- key[31] &= R_MASK_HIGH_4;
+ key[3] &= R_MASK_HIGH_4;
+ key[7] &= R_MASK_HIGH_4;
+ key[11] &= R_MASK_HIGH_4;
+ key[15] &= R_MASK_HIGH_4;
/*
* r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
*/
- key[20] &= R_MASK_LOW_2;
- key[24] &= R_MASK_LOW_2;
- key[28] &= R_MASK_LOW_2;
+ key[4] &= R_MASK_LOW_2;
+ key[8] &= R_MASK_LOW_2;
+ key[12] &= R_MASK_LOW_2;
}
/**
@@ -96,14 +96,14 @@ public class Poly1305KeyGenerator
throw new IllegalArgumentException("Poly1305 key must be 256 bits.");
}
- checkMask(key[19], R_MASK_HIGH_4);
- checkMask(key[23], R_MASK_HIGH_4);
- checkMask(key[27], R_MASK_HIGH_4);
- checkMask(key[31], R_MASK_HIGH_4);
+ checkMask(key[3], R_MASK_HIGH_4);
+ checkMask(key[7], R_MASK_HIGH_4);
+ checkMask(key[11], R_MASK_HIGH_4);
+ checkMask(key[15], R_MASK_HIGH_4);
- checkMask(key[20], R_MASK_LOW_2);
- checkMask(key[24], R_MASK_LOW_2);
- checkMask(key[28], R_MASK_LOW_2);
+ checkMask(key[4], R_MASK_LOW_2);
+ checkMask(key[8], R_MASK_LOW_2);
+ checkMask(key[12], R_MASK_LOW_2);
}
private static void checkMask(byte b, byte mask)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java b/bcprov/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
index 35131982..c0ae2a9b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
@@ -56,9 +56,9 @@ public class ECIESKeyEncapsulation
*
* @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.
+ * @param cofactorMode if true use the new cofactor ECDH.
+ * @param oldCofactorMode if true use the old cofactor ECDH.
+ * @param singleHashMode if true use single hash mode.
*/
public ECIESKeyEncapsulation(
DerivationFunction kdf,
@@ -228,7 +228,7 @@ public class ECIESKeyEncapsulation
protected KeyParameter deriveKey(int keyLen, byte[] C, byte[] PEH)
{
byte[] kdfInput = PEH;
- if (SingleHashMode)
+ if (!SingleHashMode)
{
kdfInput = Arrays.concatenate(C, PEH);
Arrays.fill(PEH, (byte)0);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java
index 7a346f1e..85a95812 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java
@@ -111,24 +111,27 @@ public class Poly1305
private void setKey(final byte[] key, final byte[] nonce)
{
+ if (key.length != 32)
+ {
+ throw new IllegalArgumentException("Poly1305 key must be 256 bits.");
+ }
if (cipher != null && (nonce == null || nonce.length != BLOCK_SIZE))
{
throw new IllegalArgumentException("Poly1305 requires a 128 bit IV.");
}
- Poly1305KeyGenerator.checkKey(key);
+ // Extract r portion of key (and "clamp" the values)
+ int t0 = Pack.littleEndianToInt(key, 0);
+ int t1 = Pack.littleEndianToInt(key, 4);
+ int t2 = Pack.littleEndianToInt(key, 8);
+ int t3 = Pack.littleEndianToInt(key, 12);
- // Extract r portion of key
- int t0 = Pack.littleEndianToInt(key, BLOCK_SIZE + 0);
- int t1 = Pack.littleEndianToInt(key, BLOCK_SIZE + 4);
- int t2 = Pack.littleEndianToInt(key, BLOCK_SIZE + 8);
- int t3 = Pack.littleEndianToInt(key, BLOCK_SIZE + 12);
-
- r0 = t0 & 0x3ffffff; t0 >>>= 26; t0 |= t1 << 6;
- r1 = t0 & 0x3ffff03; t1 >>>= 20; t1 |= t2 << 12;
- r2 = t1 & 0x3ffc0ff; t2 >>>= 14; t2 |= t3 << 18;
- r3 = t2 & 0x3f03fff; t3 >>>= 8;
- r4 = t3 & 0x00fffff;
+ // NOTE: The masks perform the key "clamping" implicitly
+ r0 = t0 & 0x03FFFFFF;
+ r1 = ((t0 >>> 26) | (t1 << 6)) & 0x03FFFF03;
+ r2 = ((t1 >>> 20) | (t2 << 12)) & 0x03FFC0FF;
+ r3 = ((t2 >>> 14) | (t3 << 18)) & 0x03F03FFF;
+ r4 = (t3 >>> 8) & 0x000FFFFF;
// Precompute multipliers
s1 = r1 * 5;
@@ -137,22 +140,27 @@ public class Poly1305
s4 = r4 * 5;
final byte[] kBytes;
+ final int kOff;
+
if (cipher == null)
{
kBytes = key;
+ kOff = BLOCK_SIZE;
}
else
{
// Compute encrypted nonce
kBytes = new byte[BLOCK_SIZE];
- cipher.init(true, new KeyParameter(key, 0, BLOCK_SIZE));
+ kOff = 0;
+
+ cipher.init(true, new KeyParameter(key, BLOCK_SIZE, BLOCK_SIZE));
cipher.processBlock(nonce, 0, kBytes, 0);
}
- k0 = Pack.littleEndianToInt(kBytes, 0);
- k1 = Pack.littleEndianToInt(kBytes, 4);
- k2 = Pack.littleEndianToInt(kBytes, 8);
- k3 = Pack.littleEndianToInt(kBytes, 12);
+ k0 = Pack.littleEndianToInt(kBytes, kOff + 0);
+ k1 = Pack.littleEndianToInt(kBytes, kOff + 4);
+ k2 = Pack.littleEndianToInt(kBytes, kOff + 8);
+ k3 = Pack.littleEndianToInt(kBytes, kOff + 12);
}
public String getAlgorithmName()
@@ -226,13 +234,13 @@ public class Poly1305
long tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
long tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
- long b;
- h0 = (int)tp0 & 0x3ffffff; b = (tp0 >>> 26);
- tp1 += b; h1 = (int)tp1 & 0x3ffffff; b = ((tp1 >>> 26) & 0xffffffff);
- tp2 += b; h2 = (int)tp2 & 0x3ffffff; b = ((tp2 >>> 26) & 0xffffffff);
- tp3 += b; h3 = (int)tp3 & 0x3ffffff; b = (tp3 >>> 26);
- tp4 += b; h4 = (int)tp4 & 0x3ffffff; b = (tp4 >>> 26);
- h0 += b * 5;
+ h0 = (int)tp0 & 0x3ffffff; tp1 += (tp0 >>> 26);
+ h1 = (int)tp1 & 0x3ffffff; tp2 += (tp1 >>> 26);
+ h2 = (int)tp2 & 0x3ffffff; tp3 += (tp2 >>> 26);
+ h3 = (int)tp3 & 0x3ffffff; tp4 += (tp3 >>> 26);
+ h4 = (int)tp4 & 0x3ffffff;
+ h0 += (int)(tp4 >>> 26) * 5;
+ h1 += (h0 >>> 26); h0 &= 0x3ffffff;
}
public int doFinal(final byte[] out, final int outOff)
@@ -250,17 +258,14 @@ public class Poly1305
processBlock();
}
- long f0, f1, f2, f3;
-
- int b = h0 >>> 26;
- h0 = h0 & 0x3ffffff;
- h1 += b; b = h1 >>> 26; h1 = h1 & 0x3ffffff;
- h2 += b; b = h2 >>> 26; h2 = h2 & 0x3ffffff;
- h3 += b; b = h3 >>> 26; h3 = h3 & 0x3ffffff;
- h4 += b; b = h4 >>> 26; h4 = h4 & 0x3ffffff;
- h0 += b * 5;
+ h1 += (h0 >>> 26); h0 &= 0x3ffffff;
+ h2 += (h1 >>> 26); h1 &= 0x3ffffff;
+ h3 += (h2 >>> 26); h2 &= 0x3ffffff;
+ h4 += (h3 >>> 26); h3 &= 0x3ffffff;
+ h0 += (h4 >>> 26) * 5; h4 &= 0x3ffffff;
+ h1 += (h0 >>> 26); h0 &= 0x3ffffff;
- int g0, g1, g2, g3, g4;
+ int g0, g1, g2, g3, g4, b;
g0 = h0 + 5; b = g0 >>> 26; g0 &= 0x3ffffff;
g1 = h1 + b; b = g1 >>> 26; g1 &= 0x3ffffff;
g2 = h2 + b; b = g2 >>> 26; g2 &= 0x3ffffff;
@@ -275,6 +280,7 @@ public class Poly1305
h3 = (h3 & nb) | (g3 & b);
h4 = (h4 & nb) | (g4 & b);
+ long f0, f1, f2, f3;
f0 = (((h0 ) | (h1 << 26)) & 0xffffffffl) + (0xffffffffL & k0);
f1 = (((h1 >>> 6 ) | (h2 << 20)) & 0xffffffffl) + (0xffffffffL & k1);
f2 = (((h2 >>> 12) | (h3 << 14)) & 0xffffffffl) + (0xffffffffL & k2);
@@ -301,6 +307,6 @@ public class Poly1305
private static final long mul32x32_64(int i1, int i2)
{
- return ((long)i1) * i2;
+ return (i1 & 0xFFFFFFFFL) * i2;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index b30b4aac..ca609ed9 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -33,6 +33,7 @@ public class GCMBlockCipher
// These fields are set by init and not modified by processing
private boolean forEncryption;
private int macSize;
+ private byte[] lastKey;
private byte[] nonce;
private byte[] initialAssociatedText;
private byte[] H;
@@ -43,6 +44,7 @@ public class GCMBlockCipher
private byte[] macBlock;
private byte[] S, S_at, S_atPre;
private byte[] counter;
+ private int blocksRemaining;
private int bufOff;
private long totalLength;
private byte[] atBlock;
@@ -94,12 +96,13 @@ public class GCMBlockCipher
this.macBlock = null;
KeyParameter keyParam;
+ byte[] newNonce = null;
if (params instanceof AEADParameters)
{
AEADParameters param = (AEADParameters)params;
- nonce = param.getNonce();
+ newNonce = param.getNonce();
initialAssociatedText = param.getAssociatedText();
int macSizeBits = param.getMacSize();
@@ -115,7 +118,7 @@ public class GCMBlockCipher
{
ParametersWithIV param = (ParametersWithIV)params;
- nonce = param.getIV();
+ newNonce = param.getIV();
initialAssociatedText = null;
macSize = 16;
keyParam = (KeyParameter)param.getParameters();
@@ -128,11 +131,32 @@ public class GCMBlockCipher
int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
this.bufBlock = new byte[bufLength];
- if (nonce == null || nonce.length < 1)
+ if (newNonce == null || newNonce.length < 1)
{
throw new IllegalArgumentException("IV must be at least 1 byte");
}
+ if (forEncryption)
+ {
+ if (nonce != null && Arrays.areEqual(nonce, newNonce))
+ {
+ if (keyParam == null)
+ {
+ throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ if (lastKey != null && Arrays.areEqual(lastKey, keyParam.getKey()))
+ {
+ throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ }
+ }
+
+ nonce = newNonce;
+ if (keyParam != null)
+ {
+ lastKey = keyParam.getKey();
+ }
+
// TODO Restrict macSize to 16 if nonce length not 12?
// Cipher always used in forward mode
@@ -176,6 +200,7 @@ public class GCMBlockCipher
this.atLength = 0;
this.atLengthPre = 0;
this.counter = Arrays.clone(J0);
+ this.blocksRemaining = -2; // page 8, len(P) <= 2^39 - 256, 1 block used by tag but done on J0
this.bufOff = 0;
this.totalLength = 0;
@@ -187,6 +212,10 @@ public class GCMBlockCipher
public byte[] getMac()
{
+ if (macBlock == null)
+ {
+ return new byte[macSize];
+ }
return Arrays.clone(macBlock);
}
@@ -448,6 +477,8 @@ public class GCMBlockCipher
{
cipher.reset();
+ // note: we do not reset the nonce.
+
S = new byte[BLOCK_SIZE];
S_at = new byte[BLOCK_SIZE];
S_atPre = new byte[BLOCK_SIZE];
@@ -456,6 +487,7 @@ public class GCMBlockCipher
atLength = 0;
atLengthPre = 0;
counter = Arrays.clone(J0);
+ blocksRemaining = -2;
bufOff = 0;
totalLength = 0;
@@ -522,6 +554,12 @@ public class GCMBlockCipher
private byte[] getNextCounterBlock()
{
+ if (blocksRemaining == 0)
+ {
+ throw new IllegalStateException("Attempt to process too many blocks");
+ }
+ blocksRemaining--;
+
int c = 1;
c += counter[15] & 0xFF; counter[15] = (byte)c; c >>>= 8;
c += counter[14] & 0xFF; counter[14] = (byte)c; c >>>= 8;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
index 86263914..78653807 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
@@ -254,6 +254,10 @@ public class OCBBlockCipher
public byte[] getMac()
{
+ if (macBlock == null)
+ {
+ return new byte[macSize];
+ }
return Arrays.clone(macBlock);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
index ed531603..ba392ab1 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
@@ -5,6 +5,9 @@ import java.math.BigInteger;
public class DHPublicKeyParameters
extends DHKeyParameters
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
private BigInteger y;
public DHPublicKeyParameters(
@@ -13,9 +16,37 @@ public class DHPublicKeyParameters
{
super(false, params);
- this.y = y;
+ this.y = validate(y, params);
}
+ private BigInteger validate(BigInteger y, DHParameters dhParams)
+ {
+ if (y == null)
+ {
+ throw new NullPointerException("y value cannot be null");
+ }
+
+ // TLS check
+ if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0)
+ {
+ throw new IllegalArgumentException("invalid DH public key");
+ }
+
+ if (dhParams.getQ() != null)
+ {
+ if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
+ {
+ return y;
+ }
+
+ throw new IllegalArgumentException("Y value does not appear to be in correct group");
+ }
+ else
+ {
+ return y; // we can't validate without Q.
+ }
+ }
+
public BigInteger getY()
{
return y;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
index c0066568..5786ee36 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
@@ -5,6 +5,9 @@ import java.math.BigInteger;
public class DSAPublicKeyParameters
extends DSAKeyParameters
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
private BigInteger y;
public DSAPublicKeyParameters(
@@ -13,9 +16,27 @@ public class DSAPublicKeyParameters
{
super(false, params);
- this.y = y;
+ this.y = validate(y, params);
}
+ private BigInteger validate(BigInteger y, DSAParameters params)
+ {
+ if (params != null)
+ {
+ if (TWO.compareTo(y) <= 0 && params.getP().subtract(TWO).compareTo(y) >= 0
+ && ONE.equals(y.modPow(params.getQ(), params.getP())))
+ {
+ return y;
+ }
+
+ throw new IllegalArgumentException("y value does not appear to be in correct group");
+ }
+ else
+ {
+ return y; // we can't validate without params, fortunately we can't use the key either...
+ }
+ }
+
public BigInteger getY()
{
return y;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
index 9cc6e727..c97f2e76 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
@@ -71,4 +71,34 @@ public class ECDomainParameters
{
return Arrays.clone(seed);
}
+
+ public boolean equals(
+ Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if ((obj instanceof ECDomainParameters))
+ {
+ ECDomainParameters other = (ECDomainParameters)obj;
+
+ return this.curve.equals(other.curve) && this.G.equals(other.G) && this.n.equals(other.n) && this.h.equals(other.h);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ int hc = curve.hashCode();
+ hc *= 37;
+ hc ^= G.hashCode();
+ hc *= 37;
+ hc ^= n.hashCode();
+ hc *= 37;
+ hc ^= h.hashCode();
+ return hc;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
index b6b3fb6d..036bf4ae 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
@@ -5,14 +5,37 @@ import org.bouncycastle.math.ec.ECPoint;
public class ECPublicKeyParameters
extends ECKeyParameters
{
- ECPoint Q;
+ private final ECPoint Q;
public ECPublicKeyParameters(
ECPoint Q,
ECDomainParameters params)
{
super(false, params);
- this.Q = Q.normalize();
+
+ this.Q = validate(Q);
+ }
+
+ private ECPoint validate(ECPoint q)
+ {
+ if (q == null)
+ {
+ throw new IllegalArgumentException("point has null value");
+ }
+
+ if (q.isInfinity())
+ {
+ throw new IllegalArgumentException("point at infinity");
+ }
+
+ q = q.normalize();
+
+ if (!q.isValid())
+ {
+ throw new IllegalArgumentException("point not on curve");
+ }
+
+ return q;
}
public ECPoint getQ()
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPrivateParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPrivateParameters.java
index 832c07fd..8be6f0e2 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPrivateParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPrivateParameters.java
@@ -21,6 +21,32 @@ public class MQVPrivateParameters
ECPrivateKeyParameters ephemeralPrivateKey,
ECPublicKeyParameters ephemeralPublicKey)
{
+ if (staticPrivateKey == null)
+ {
+ throw new NullPointerException("staticPrivateKey cannot be null");
+ }
+ if (ephemeralPrivateKey == null)
+ {
+ throw new NullPointerException("ephemeralPrivateKey cannot be null");
+ }
+
+ ECDomainParameters parameters = staticPrivateKey.getParameters();
+ if (!parameters.equals(ephemeralPrivateKey.getParameters()))
+ {
+ throw new IllegalArgumentException("Static and ephemeral private keys have different domain parameters");
+ }
+
+ if (ephemeralPublicKey == null)
+ {
+ ephemeralPublicKey = new ECPublicKeyParameters(
+ parameters.getG().multiply(ephemeralPrivateKey.getD()),
+ parameters);
+ }
+ else if (!parameters.equals(ephemeralPublicKey.getParameters()))
+ {
+ throw new IllegalArgumentException("Ephemeral public key has different domain parameters");
+ }
+
this.staticPrivateKey = staticPrivateKey;
this.ephemeralPrivateKey = ephemeralPrivateKey;
this.ephemeralPublicKey = ephemeralPublicKey;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPublicParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPublicParameters.java
index b3b24671..0b3ac7d6 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPublicParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/MQVPublicParameters.java
@@ -12,6 +12,19 @@ public class MQVPublicParameters
ECPublicKeyParameters staticPublicKey,
ECPublicKeyParameters ephemeralPublicKey)
{
+ if (staticPublicKey == null)
+ {
+ throw new NullPointerException("staticPublicKey cannot be null");
+ }
+ if (ephemeralPublicKey == null)
+ {
+ throw new NullPointerException("ephemeralPublicKey cannot be null");
+ }
+ if (!staticPublicKey.getParameters().equals(ephemeralPublicKey.getParameters()))
+ {
+ throw new IllegalArgumentException("Static and ephemeral public keys have different domain parameters");
+ }
+
this.staticPublicKey = staticPublicKey;
this.ephemeralPublicKey = ephemeralPublicKey;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
index 4a2d9354..c357843e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
@@ -5,6 +5,8 @@ import java.math.BigInteger;
public class RSAKeyParameters
extends AsymmetricKeyParameter
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
private BigInteger modulus;
private BigInteger exponent;
@@ -15,10 +17,40 @@ public class RSAKeyParameters
{
super(isPrivate);
- this.modulus = modulus;
+ if (!isPrivate)
+ {
+ if ((exponent.intValue() & 1) == 0)
+ {
+ throw new IllegalArgumentException("RSA publicExponent is even");
+ }
+ }
+
+ this.modulus = validate(modulus);
this.exponent = exponent;
}
+ private BigInteger validate(BigInteger modulus)
+ {
+ if ((modulus.intValue() & 1) == 0)
+ {
+ throw new IllegalArgumentException("RSA modulus is even");
+ }
+
+ // the value is the product of the 132 smallest primes from 3 to 751
+ if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" +
+ "931517706595657435907891265414916764399268423699130577757433083166" +
+ "651158914570105971074227669275788291575622090199821297575654322355" +
+ "049043101306108213104080801056529374892690144291505781966373045481" +
+ "8359472391642885328171302299245556663073719855")).equals(ONE))
+ {
+ throw new IllegalArgumentException("RSA modulus has a small prime factor");
+ }
+
+ // TODO: add additional primePower/Composite test - expensive!!
+
+ return modulus;
+ }
+
public BigInteger getModulus()
{
return modulus;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
index e6007927..9c096804 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
@@ -44,8 +44,8 @@ public class SP800SecureRandomBuilder
* Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
* the passed in SecureRandom does for its generateSeed() call.
* </p>
- * @param entropySource
- * @param predictionResistant
+ * @param entropySource the SecureRandom acting as a source of entropy for DRBGs made by this builder.
+ * @param predictionResistant true if the SecureRandom seeder can be regarded as predictionResistant.
*/
public SP800SecureRandomBuilder(SecureRandom entropySource, boolean predictionResistant)
{
@@ -144,35 +144,6 @@ public class SP800SecureRandomBuilder
return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new HMacDRBGProvider(hMac, nonce, personalizationString, securityStrength), predictionResistant);
}
- /**
- * Build a SecureRandom based on a SP 800-90A Dual EC DRBG using the NIST point set.
- *
- * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
- * @param nonce nonce value to use in DRBG construction.
- * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
- * @return a SecureRandom supported by a Dual EC DRBG.
- */
- public SP800SecureRandom buildDualEC(Digest digest, byte[] nonce, boolean predictionResistant)
- {
- return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new DualECDRBGProvider(digest, nonce, personalizationString, securityStrength), predictionResistant);
- }
-
- /**
- * Build a SecureRandom based on a SP 800-90A Dual EC DRBG according to a defined point set.
- *
- * @param pointSet an array of DualECPoints to use for DRB generation.
- * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
- * @param nonce nonce value to use in DRBG construction.
- * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
- * @return a SecureRandom supported by a Dual EC DRBG.
- * @deprecated Don't use this for anything other than research purposes. It appears this construct is simply not safe.
- */
- public SP800SecureRandom buildDualEC(DualECPoints[] pointSet, Digest digest, byte[] nonce, boolean predictionResistant)
- {
- return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new ConfigurableDualECDRBGProvider(pointSet, digest, nonce, personalizationString, securityStrength), predictionResistant);
- }
-
-
private static class HashDRBGProvider
implements DRBGProvider
{
@@ -195,53 +166,6 @@ public class SP800SecureRandomBuilder
}
}
- private static class DualECDRBGProvider
- implements DRBGProvider
- {
- private final Digest digest;
- private final byte[] nonce;
- private final byte[] personalizationString;
- private final int securityStrength;
-
- public DualECDRBGProvider(Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
- {
- this.digest = digest;
- this.nonce = nonce;
- this.personalizationString = personalizationString;
- this.securityStrength = securityStrength;
- }
-
- public SP80090DRBG get(EntropySource entropySource)
- {
- return new DualECSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce);
- }
- }
-
- private static class ConfigurableDualECDRBGProvider
- implements DRBGProvider
- {
- private final DualECPoints[] pointSet;
- private final Digest digest;
- private final byte[] nonce;
- private final byte[] personalizationString;
- private final int securityStrength;
-
- public ConfigurableDualECDRBGProvider(DualECPoints[] pointSet, Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
- {
- this.pointSet = new DualECPoints[pointSet.length];
- System.arraycopy(pointSet, 0, this.pointSet, 0, pointSet.length);
- this.digest = digest;
- this.nonce = nonce;
- this.personalizationString = personalizationString;
- this.securityStrength = securityStrength;
- }
-
- public SP80090DRBG get(EntropySource entropySource)
- {
- return new DualECSP800DRBG(pointSet, digest, securityStrength, entropySource, personalizationString, nonce);
- }
- }
-
private static class HMacDRBGProvider
implements DRBGProvider
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
index a8506a1a..3dfe115d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
@@ -143,66 +143,6 @@ public class SP800RandomTest
}
}
- private void testDualECRandom()
- {
- DRBGTestVector tv = new DRBGTestVector(
- new SHA256Digest(),
- new SHA256EntropyProvider().get(128),
- false,
- "2021222324252627",
- 128,
- new String[]
- {
- "3AB095CC493A8730D70DE923108B2E4710799044FFC27D0A1156250DDF97E8B05ACE055E49F3E3F5B928CCD18317A3E68FCB0B6F0459ADF9ECF79C87",
- "7B902FC35B0AF50F57F8822936D08A96E41B16967C6B1AA0BC05032F0D53919DC587B664C883E2FE8F3948002FCD8BCBFC4706BCAA2075EF6BF41167"
- })
- .setPersonalizationString("404142434445464748494A4B4C4D4E4F");
-
- doDualECTest(1, tv);
-
- tv = new DRBGTestVector(
- new SHA256Digest(),
- new SHA256EntropyProvider().get(128),
- true,
- "2021222324252627",
- 128,
- new String[]
- {
- "8C77288EDBEA9A742464F78D55E33593C1BF5F9D8CD8609D6D53BAC4E4B42252A227A99BAD0F2358B05955CD35723B549401C71C9C1F32F8A2018E24",
- "56ECA61C64F69C1C232E992623C71418BD0B96D783118FAAD94A09E3A9DB74D15E805BA7F14625995CA77612B2EF7A05863699ECBABF70D3D422C014"
- });
-
- doDualECTest(2, tv);
- }
-
- private void doDualECTest(int index, DRBGTestVector tv)
- {
- SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new SHA256EntropyProvider());
-
- rBuild.setPersonalizationString(tv.personalizationString());
- rBuild.setSecurityStrength(tv.securityStrength());
- rBuild.setEntropyBitsRequired(tv.securityStrength());
-
- SecureRandom random = rBuild.buildDualEC(tv.getDigest(), tv.nonce(), tv.predictionResistance());
-
- byte[] expected = tv.expectedValue(0);
- byte[] produced = new byte[expected.length];
-
- random.nextBytes(produced);
- if (!Arrays.areEqual(expected, produced))
- {
- fail(index + " SP800 Dual EC SecureRandom produced incorrect result (1)");
- }
-
- random.nextBytes(produced);
- expected = tv.expectedValue(1);
-
- if (!Arrays.areEqual(expected, produced))
- {
- fail(index + " SP800 Dual EC SecureRandom produced incorrect result (2)");
- }
- }
-
private void testCTRRandom()
{
DRBGTestVector tv = new DRBGTestVector(
@@ -299,7 +239,6 @@ public class SP800RandomTest
testHashRandom();
testHMACRandom();
testCTRRandom();
- testDualECRandom();
testGenerateSeed();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
index 44f838b2..920611bc 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
@@ -95,7 +95,8 @@ public class DSASigner
BigInteger k = kCalculator.nextK();
- BigInteger r = params.getG().modPow(k, params.getP()).mod(q);
+ // the randomizer is to conceal timing information related to k and x.
+ BigInteger r = params.getG().modPow(k.add(getRandomizer(q, random)), params.getP()).mod(q);
k = k.modInverse(q).multiply(m.add(x.multiply(r)));
@@ -163,4 +164,12 @@ public class DSASigner
{
return !needed ? null : (provided != null) ? provided : new SecureRandom();
}
+
+ private BigInteger getRandomizer(BigInteger q, SecureRandom provided)
+ {
+ // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r.
+ int randomBits = 7;
+
+ return new BigInteger(randomBits, provided != null ? provided : new SecureRandom()).add(BigInteger.valueOf(128)).multiply(q);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
index 69d9918f..3db79583 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -51,6 +51,11 @@ public class RSADigestSigner
oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224);
oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256);
+ oidMap.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224);
+ oidMap.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256);
+ oidMap.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384);
+ oidMap.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512);
+
oidMap.put("MD2", PKCSObjectIdentifiers.md2);
oidMap.put("MD4", PKCSObjectIdentifiers.md4);
oidMap.put("MD5", PKCSObjectIdentifiers.md5);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/AESWrapPadTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/AESWrapPadTest.java
index 41ae613b..f8769e8e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/AESWrapPadTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/AESWrapPadTest.java
@@ -5,6 +5,7 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.engines.AESWrapPadEngine;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -69,6 +70,31 @@ public class AESWrapPadTest
}
}
+ private void wrapWithIVTest()
+ throws Exception
+ {
+ byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8");
+ byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738");
+ byte[] expected = Hex.decode("5cbdb3fb71351d0e628b85dbcba1a1890d4db26d1335e11d1aabea11124caad0");
+
+ Wrapper wrapper = new AESWrapPadEngine();
+
+ wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333")));
+
+ byte[] cipherText = wrapper.wrap(key, 0, key.length);
+ if (!areEqual(cipherText, expected))
+ {
+ fail("Wrapped value does not match expected.");
+ }
+ wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333")));
+ byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length);
+
+ if (!areEqual(key, plainText))
+ {
+ fail("Unwrapped value does not match original.");
+ }
+ }
+
public String getName()
{
return "AESWrapPad";
@@ -88,6 +114,7 @@ public class AESWrapPadTest
key = Hex.decode("466f7250617369");
wrapAndUnwrap(kek, key, wrap);
+ wrapWithIVTest();
//
// offset test
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/Blake2bDigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/Blake2bDigestTest.java
index e962af94..7f4a6d35 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/Blake2bDigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/Blake2bDigestTest.java
@@ -133,7 +133,8 @@ public class Blake2bDigestTest
{
blake2bunkeyed.update(unkeyedInput[j]);
}
- } catch (UnsupportedEncodingException e)
+ }
+ catch (UnsupportedEncodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
@@ -150,6 +151,94 @@ public class Blake2bDigestTest
new String(Hex.encode(unkeyedHash)));
}
}
+
+ cloneTest();
+ resetTest();
+ }
+
+ private void cloneTest()
+ {
+ Blake2bDigest blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, Hex.decode("000102030405060708090a0b0c0d0e0f"), Hex.decode("101112131415161718191a1b1c1d1e1f"));
+ byte[] expected = Hex.decode("b6d48ed5771b17414c4e08bd8d8a3bc4");
+
+ checkClone(blake2bCloneSource, expected);
+
+ // just digest size
+ blake2bCloneSource = new Blake2bDigest(160);
+ expected = Hex.decode("64202454e538279b21cea0f5a7688be656f8f484");
+ checkClone(blake2bCloneSource, expected);
+
+ // null salt and personalisation
+ blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, null, null);
+ expected = Hex.decode("2b4a081fae2d7b488f5eed7e83e42a20");
+ checkClone(blake2bCloneSource, expected);
+
+ // null personalisation
+ blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, Hex.decode("000102030405060708090a0b0c0d0e0f"), null);
+ expected = Hex.decode("00c3a2a02fcb9f389857626e19d706f6");
+ checkClone(blake2bCloneSource, expected);
+
+ // null salt
+ blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, null, Hex.decode("101112131415161718191a1b1c1d1e1f"));
+ expected = Hex.decode("f445ec9c062a3c724f8fdef824417abb");
+ checkClone(blake2bCloneSource, expected);
+ }
+
+ private void checkClone(Blake2bDigest blake2bCloneSource, byte[] expected)
+ {
+ byte[] message = Hex.decode(keyedTestVectors[3][0]);
+
+ blake2bCloneSource.update(message, 0, message.length);
+
+ byte[] hash = new byte[blake2bCloneSource.getDigestSize()];
+
+ Blake2bDigest digClone = new Blake2bDigest(blake2bCloneSource);
+
+ blake2bCloneSource.doFinal(hash, 0);
+ if (!areEqual(expected, hash))
+ {
+ fail("clone source not correct");
+ }
+
+ digClone.doFinal(hash, 0);
+ if (!areEqual(expected, hash))
+ {
+ fail("clone not correct");
+ }
+ }
+
+ private void resetTest()
+ {
+ // Generate a non-zero key
+ byte[] key = new byte[32];
+ for (byte i = 0; i < key.length; i++)
+ {
+ key[i] = i;
+ }
+ // Generate some non-zero input longer than the key
+ byte[] input = new byte[key.length + 1];
+ for (byte i = 0; i < input.length; i++)
+ {
+ input[i] = i;
+ }
+ // Hash the input
+ Blake2bDigest digest = new Blake2bDigest(key);
+ digest.update(input, 0, input.length);
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ // Using a second instance, hash the input without calling doFinal()
+ Blake2bDigest digest1 = new Blake2bDigest(key);
+ digest1.update(input, 0, input.length);
+ // Reset the second instance and hash the input again
+ digest1.reset();
+ digest1.update(input, 0, input.length);
+ byte[] hash1 = new byte[digest.getDigestSize()];
+ digest1.doFinal(hash1, 0);
+ // The hashes should be identical
+ if (!Arrays.areEqual(hash, hash1))
+ {
+ fail("state was not reset");
+ }
}
public static void main(String[] args) throws Exception
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/CipherStreamTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/CipherStreamTest.java
index 089e4ed8..48c0d0cf 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/CipherStreamTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/CipherStreamTest.java
@@ -43,7 +43,6 @@ import org.bouncycastle.crypto.modes.CCMBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.modes.CTSBlockCipher;
import org.bouncycastle.crypto.modes.EAXBlockCipher;
-import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.NISTCTSBlockCipher;
import org.bouncycastle.crypto.modes.OCBBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
@@ -553,7 +552,8 @@ public class CipherStreamTest
if (blockSize == 16)
{
testMode(new CCMBlockCipher(cipher1), new ParametersWithIV(key, new byte[7]));
- testMode(new GCMBlockCipher(cipher1), withIv);
+ // TODO: need to have a GCM safe version of testMode.
+// testMode(new GCMBlockCipher(cipher1), withIv);
testMode(new OCBBlockCipher(cipher1, cipher2), new ParametersWithIV(key, new byte[15]));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/DSATest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/DSATest.java
index 02c748fa..5f1a1f86 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/DSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/DSATest.java
@@ -3,9 +3,12 @@ package org.bouncycastle.crypto.test;
import java.math.BigInteger;
import java.security.SecureRandom;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
@@ -15,12 +18,16 @@ 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.DSADigestSigner;
import org.bouncycastle.crypto.signers.DSASigner;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
+import org.bouncycastle.util.test.TestRandomData;
/**
* Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors.
@@ -31,12 +38,14 @@ public class DSATest
byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
- SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2});
+ SecureRandom random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) });
byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
- SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData });
-
+ SecureRandom keyRandom = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(Hex.decode("01020304"))});
+
BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16);
BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16);
@@ -103,6 +112,106 @@ public class DSATest
dsa2Test2();
dsa2Test3();
dsa2Test4();
+
+ testDSAsha3(224, new BigInteger("613202af2a7f77e02b11b5c3a5311cf6b412192bc0032aac3ec127faebfc6bd0", 16));
+ testDSAsha3(256, new BigInteger("2450755c5e15a691b121bc833b97864e34a61ee025ecec89289c949c1858091e", 16));
+ testDSAsha3(384, new BigInteger("7aad97c0b71bb1e1a6483b6948a03bbe952e4780b0cee699a11731f90d84ddd1", 16));
+ testDSAsha3(512, new BigInteger("725ad64d923c668e64e7c3898b5efde484cab49ce7f98c2885d2a13a9e355ad4", 16));
+ }
+
+ private void testDSAsha3(int size, BigInteger s)
+ {
+ DSAParameters dsaParams = new DSAParameters(
+ new BigInteger(
+ "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+ "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+ "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+ "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+ "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+ "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+ "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+ "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+ "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+ "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+ "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16),
+ new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16),
+ new BigInteger(
+ "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+ "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+ "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+ "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+ "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+ "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+ "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+ "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+ "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+ "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+ "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)
+ );
+
+ BigInteger x = new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16);
+
+ BigInteger y = new BigInteger(
+ "2828003D7C747199143C370FDD07A286" +
+ "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+ "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+ "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+ "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+ "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+ "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+ "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+ "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+ "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+ "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16);
+
+ DSAPrivateKeyParameters priKey = new DSAPrivateKeyParameters(x, dsaParams);
+ SecureRandom k = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] {
+ new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))),
+ new FixedSecureRandom.Data(Hex.decode("01020304"))
+ });
+
+ byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
+
+ DSADigestSigner dsa = new DSADigestSigner(new DSASigner(), new SHA3Digest(size));
+
+ dsa.init(true, new ParametersWithRandom(priKey, k));
+
+ dsa.update(M, 0, M.length);
+
+ byte[] encSig = dsa.generateSignature();
+
+ ASN1Sequence sig = ASN1Sequence.getInstance(encSig);
+
+ BigInteger r = new BigInteger("4864074fe30e6601268ee663440e4d9b703f62673419864e91e9edb0338ce510", 16);
+
+ BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue();
+ if (!r.equals(sigR))
+ {
+ fail("r component wrong." + Strings.lineSeparator()
+ + " expecting: " + r.toString(16) + Strings.lineSeparator()
+ + " got : " + sigR.toString(16));
+ }
+
+ BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue();
+ if (!s.equals(sigS))
+ {
+ fail("s component wrong." + Strings.lineSeparator()
+ + " expecting: " + s.toString(16) + Strings.lineSeparator()
+ + " got : " + sigS.toString(16));
+ }
+
+ // Verify the signature
+ DSAPublicKeyParameters pubKey = new DSAPublicKeyParameters(y, dsaParams);
+
+ dsa.init(false, pubKey);
+
+ dsa.update(M, 0, M.length);
+
+ if (!dsa.verifySignature(encSig))
+ {
+ fail("signature fails");
+ }
}
private void dsa2Test1()
@@ -156,7 +265,7 @@ public class DSATest
DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
- kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), params));
+ kpGen.init(new DSAKeyGenerationParameters(new TestRandomBigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16), params));
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
@@ -182,7 +291,10 @@ public class DSATest
DSASigner signer = new DSASigner();
- signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075"))));
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(
+ new FixedSecureRandom.Source[] {
+ new FixedSecureRandom.BigInteger("349C55648DCF992F3F33E8026CFAC87C1D2BA075"),
+ new FixedSecureRandom.Data(Hex.decode("01020304")) })));
byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D");
@@ -268,7 +380,7 @@ public class DSATest
DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
- kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params));
+ kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params));
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
@@ -299,7 +411,11 @@ public class DSATest
DSASigner signer = new DSASigner();
- signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05"))));
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(
+ new FixedSecureRandom.Source[] {
+ new FixedSecureRandom.BigInteger(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")),
+ new FixedSecureRandom.Data(Hex.decode("01020304"))
+ })));
byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
@@ -384,7 +500,7 @@ public class DSATest
DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
- kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params));
+ kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params));
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
@@ -415,7 +531,11 @@ public class DSATest
DSASigner signer = new DSASigner();
- signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))));
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(
+ new FixedSecureRandom.Source[] {
+ new FixedSecureRandom.BigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")),
+ new FixedSecureRandom.Data(Hex.decode("01020304"))
+ })));
byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
@@ -510,7 +630,7 @@ public class DSATest
DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator();
- kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params));
+ kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params));
AsymmetricCipherKeyPair kp = kpGen.generateKeyPair();
@@ -546,7 +666,10 @@ public class DSATest
DSASigner signer = new DSASigner();
- signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"))));
+ signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(
+ new FixedSecureRandom.Source[]
+ { new FixedSecureRandom.BigInteger("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"),
+ new FixedSecureRandom.Data(Hex.decode("01020304")) })));
byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
@@ -577,7 +700,7 @@ public class DSATest
}
private class DSATestSecureRandom
- extends FixedSecureRandom
+ extends TestRandomData
{
private boolean first = true;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/DSTU4145Test.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/DSTU4145Test.java
index 2d3013d4..d26e3252 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/DSTU4145Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/DSTU4145Test.java
@@ -12,8 +12,8 @@ import org.bouncycastle.crypto.signers.DSTU4145Signer;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomData;
public class DSTU4145Test
extends SimpleTest
@@ -34,7 +34,7 @@ public class DSTU4145Test
private void test163()
throws Exception
{
- SecureRandom random = new FixedSecureRandom(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6"));
+ SecureRandom random = new TestRandomData(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6"));
byte[] hash = Hex.decode("09c9c44277910c9aaee486883a2eb95b7180166ddf73532eeb76edaef52247ff");
for (int i = 0; i < hash.length / 2; i++)
@@ -82,7 +82,7 @@ public class DSTU4145Test
private void test173()
throws Exception
{
- SecureRandom random = new FixedSecureRandom(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F"));
+ SecureRandom random = new TestRandomData(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F"));
byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8");
for (int i = 0; i < hash.length / 2; i++)
@@ -130,7 +130,7 @@ public class DSTU4145Test
private void test283()
throws Exception
{
- SecureRandom random = new FixedSecureRandom(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E"));
+ SecureRandom random = new TestRandomData(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E"));
byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8");
for (int i = 0; i < hash.length / 2; i++)
@@ -178,7 +178,7 @@ public class DSTU4145Test
private void test431()
throws Exception
{
- SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457"));
+ SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457"));
byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8");
for (int i = 0; i < hash.length / 2; i++)
@@ -225,7 +225,7 @@ public class DSTU4145Test
private void testTruncation()
{
- SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457"));
+ SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457"));
// use extra long "hash" with set bits...
byte[] hash = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/DeterministicDSATest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/DeterministicDSATest.java
index c47cf8e8..ed543324 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/DeterministicDSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/DeterministicDSATest.java
@@ -11,6 +11,7 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
@@ -60,6 +61,11 @@ public class DeterministicDSATest
doTestHMACDetDSATest(new SHA384Digest(), privKey, new BigInteger("854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", 16), new BigInteger("91D0E0F53E22F898D158380676A871A157CDA622", 16));
doTestHMACDetDSATest(new SHA512Digest(), privKey, new BigInteger("8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", 16), new BigInteger("7C670C7AD72B6C050C109E1790008097125433E8", 16));
+ doTestHMACDetDSATest(new SHA3Digest(224), privKey, new BigInteger("58748b6ca41d25e41f7bfa51fed204a10a1bd1d3", 16), new BigInteger("86de2fdad0bc848dd20ddd9dc6253fc6d7553268", 16));
+ doTestHMACDetDSATest(new SHA3Digest(256), privKey, new BigInteger("98c7a7906ada494285b3ab15cf9188a425f26bd4", 16), new BigInteger("21c5ed876037470d3959fa12f918674a4bf190e9", 16));
+ doTestHMACDetDSATest(new SHA3Digest(384), privKey, new BigInteger("445ec584ec15c14abc67c99886a30a286cc83b33", 16), new BigInteger("21f564d5bb4b175e89a1a6fb2f27cd34c861142d", 16));
+ doTestHMACDetDSATest(new SHA3Digest(512), privKey, new BigInteger("16918083f4c3ff4fc9b327e9e120a30ec39faaf6", 16), new BigInteger("1e9183a1dc7c20dbb596920cd94da3844a087203", 16));
+
dsaParameters = new DSAParameters(
new BigInteger("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" +
"C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" +
@@ -124,6 +130,11 @@ public class DeterministicDSATest
doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16));
doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16));
+ doTestHMACDetECDSATest(new SHA3Digest(224), privKey, new BigInteger("abfcb817d04cc223f0d9c02c6db9230a91f955bf4556e0c6", 16), new BigInteger("ec2c29065a50d8ea39533d49472ccf538a5388cb31900e8f", 16));
+ doTestHMACDetECDSATest(new SHA3Digest(256), privKey, new BigInteger("a2c2d5362d3cea77191edb239bf22a14dcc59d6500a744fc", 16), new BigInteger("6c63f3012353082026be7e2c6f37e6d7811066ddc9b9ee47", 16));
+ doTestHMACDetECDSATest(new SHA3Digest(384), privKey, new BigInteger("2ff2c37d48cd6691c8adb9d2b1c1af203a1a6b8769c588dd", 16), new BigInteger("79c8171097f845c608dafd218ba096a51e0e4882faf2c08d", 16));
+ doTestHMACDetECDSATest(new SHA3Digest(512), privKey, new BigInteger("384619b82461f4cc852dfa1e87cd87105e8eb3cfd0fb6461", 16), new BigInteger("d0aac03f72e90942821e3af1f77fd8a6ae82d1ed31b8ed06", 16));
+
x9ECParameters = NISTNamedCurves.getByName("P-224");
ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
@@ -484,11 +495,11 @@ public class DeterministicDSATest
if (!r.equals(rs[0]))
{
- fail("r value wrong");
+ fail("r value wrong, got " + rs[0].toString(16));
}
if (!s.equals(rs[1]))
{
- fail("s value wrong");
+ fail("s value wrong, got " + rs[1].toString(16));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/DigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/DigestTest.java
index 09f52f46..f2843515 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/DigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/DigestTest.java
@@ -36,7 +36,7 @@ public abstract class DigestTest
for (int i = 0; i < input.length - 1; i++)
{
byte[] m = toByteArray(input[i]);
-
+
vectorTest(digest, i, resBuf, m, Hex.decode(results[i]));
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/EAXTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/EAXTest.java
index 401d9fa3..7eb8582e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/EAXTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/EAXTest.java
@@ -4,7 +4,6 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.EAXBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
@@ -118,7 +117,7 @@ public class EAXTest
checkVectors(10, K10, 128, N10, A10, P10, T10, C10);
checkVectors(11, K11, 32, N11, A11, P11, T11, C11);
- EAXBlockCipher eax = new EAXBlockCipher(new AESFastEngine());
+ EAXBlockCipher eax = new EAXBlockCipher(new AESEngine());
ivParamTest(1, eax, K1, N1);
//
@@ -195,8 +194,8 @@ public class EAXTest
byte[] c)
throws InvalidCipherTextException
{
- EAXBlockCipher encEax = new EAXBlockCipher(new AESFastEngine());
- EAXBlockCipher decEax = new EAXBlockCipher(new AESFastEngine());
+ EAXBlockCipher encEax = new EAXBlockCipher(new AESEngine());
+ EAXBlockCipher decEax = new EAXBlockCipher(new AESEngine());
AEADParameters parameters = new AEADParameters(new KeyParameter(k), macSize, n, a);
encEax.init(true, parameters);
@@ -326,7 +325,7 @@ public class EAXTest
srng.nextBytes(datIn);
srng.nextBytes(key);
- AESFastEngine engine = new AESFastEngine();
+ AESEngine engine = new AESEngine();
KeyParameter sessKey = new KeyParameter(key);
EAXBlockCipher eaxCipher = new EAXBlockCipher(engine);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECGOST3410Test.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECGOST3410Test.java
index 175835cd..291c3056 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECGOST3410Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECGOST3410Test.java
@@ -15,8 +15,8 @@ import org.bouncycastle.crypto.signers.ECGOST3410Signer;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomData;
/**
* ECGOST3410 tests are taken from GOST R 34.10-2001.
@@ -34,7 +34,7 @@ public class ECGOST3410Test
byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").toByteArray();
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomData(kData);
private void ecGOST3410_TEST()
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECNRTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECNRTest.java
index d4cf7419..7c1b238c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECNRTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECNRTest.java
@@ -12,8 +12,8 @@ import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
/**
* ECNR tests.
@@ -29,7 +29,7 @@ public class ECNRTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(true, kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
private void ecNR239bitPrime()
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECTest.java
index 46ed3f0d..61e4fc84 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/ECTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/ECTest.java
@@ -3,6 +3,8 @@ package org.bouncycastle.crypto.test;
import java.math.BigInteger;
import java.security.SecureRandom;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
@@ -11,6 +13,7 @@ import org.bouncycastle.crypto.BasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
@@ -19,6 +22,7 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.MQVPrivateParameters;
import org.bouncycastle.crypto.params.MQVPublicParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.DSADigestSigner;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
@@ -26,15 +30,15 @@ import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
/**
* ECDSA tests are taken from X9.62.
*/
public class ECTest
extends SimpleTest
-{
+{
/**
* X9.62 - 1998,<br>
* J.3.1, Page 152, ECDSA over the field Fp<br>
@@ -47,7 +51,7 @@ public class ECTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("6140507067065001063065065565667405560006161556565665656654"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081");
@@ -58,9 +62,9 @@ public class ECTest
n, ECConstants.ONE);
ECDomainParameters params = new ECDomainParameters(
- curve,
- curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
- n);
+ curve,
+ curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+ n);
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d
@@ -104,10 +108,10 @@ public class ECTest
private void decodeTest()
{
ECCurve.Fp curve = new ECCurve.Fp(
- new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
- new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
- new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
-
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+ new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
+
ECPoint p = curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")).normalize();
if (!p.getAffineXCoord().toBigInteger().equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16)))
@@ -127,7 +131,7 @@ public class ECTest
fail("point compressed incorrectly");
}
}
-
+
/**
* X9.62 - 1998,<br>
* J.3.2, Page 155, ECDSA over the field Fp<br>
@@ -140,7 +144,7 @@ public class ECTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(true, kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
@@ -203,10 +207,10 @@ public class ECTest
{
BigInteger r = new BigInteger("87194383164871543355722284926904419997237591535066528048");
BigInteger s = new BigInteger("308992691965804947361541664549085895292153777025772063598");
-
+
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("1542725565216523985789236956265265265235675811949404040041"));
-
- SecureRandom k = new FixedSecureRandom(kData);
+
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger n = new BigInteger("1569275433846670190958947355803350458831205595451630533029");
BigInteger h = BigInteger.valueOf(2);
@@ -226,29 +230,29 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("1275552191113212300012030439187146164646146646466749494799"), // d
params);
-
+
ECDSASigner ecdsa = new ECDSASigner();
ParametersWithRandom param = new ParametersWithRandom(priKey, k);
-
+
ecdsa.init(true, param);
-
+
byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray();
BigInteger[] sig = ecdsa.generateSignature(message);
-
+
if (!r.equals(sig[0]))
{
fail("r component wrong." + Strings.lineSeparator()
+ " expecting: " + r + Strings.lineSeparator()
+ " got : " + sig[0]);
}
-
+
if (!s.equals(sig[1]))
{
fail("s component wrong." + Strings.lineSeparator()
+ " expecting: " + s + Strings.lineSeparator()
+ " got : " + sig[1]);
}
-
+
// Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
curve.decodePoint(Hex.decode("045DE37E756BD55D72E3768CB396FFEB962614DEA4CE28A2E755C0E0E02F5FB132CAF416EF85B229BBB8E1352003125BA1")), // Q
@@ -271,10 +275,10 @@ public class ECTest
{
BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
-
+
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
-
- SecureRandom k = new FixedSecureRandom(kData);
+
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783");
BigInteger h = BigInteger.valueOf(4);
@@ -294,29 +298,29 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
params);
-
+
ECDSASigner ecdsa = new ECDSASigner();
ParametersWithRandom param = new ParametersWithRandom(priKey, k);
-
+
ecdsa.init(true, param);
-
+
byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray();
BigInteger[] sig = ecdsa.generateSignature(message);
-
+
if (!r.equals(sig[0]))
{
fail("r component wrong." + Strings.lineSeparator()
+ " expecting: " + r + Strings.lineSeparator()
+ " got : " + sig[0]);
}
-
+
if (!s.equals(sig[1]))
{
fail("s component wrong." + Strings.lineSeparator()
+ " expecting: " + s + Strings.lineSeparator()
+ " got : " + sig[1]);
}
-
+
// Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
@@ -337,8 +341,8 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d
params);
- SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
-
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
+
byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79");
ECDSASigner dsa = new ECDSASigner();
@@ -349,7 +353,7 @@ public class ECTest
BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742");
BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978");
-
+
if (!r.equals(sig[0]))
{
fail("r component wrong." + Strings.lineSeparator()
@@ -364,7 +368,7 @@ public class ECTest
+ " got : " + sig[1]);
}
- // Verify the signature
+ // Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q
params);
@@ -383,8 +387,8 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("BE6F6E91FE96840A6518B56F3FE21689903A64FA729057AB872A9F51", 16), // d
params);
- SecureRandom k = new FixedSecureRandom(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3"));
-
+ SecureRandom k = new TestRandomBigInteger(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3"));
+
byte[] M = Hex.decode("E5D5A7ADF73C5476FAEE93A2C76CE94DC0557DB04CDC189504779117920B896D");
ECDSASigner dsa = new ECDSASigner();
@@ -410,7 +414,7 @@ public class ECTest
+ " got : " + sig[1]);
}
- // Verify the signature
+ // Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
params.getCurve().decodePoint(Hex.decode("04C5C9B38D3603FCCD6994CBB9594E152B658721E483669BB42728520F484B537647EC816E58A8284D3B89DFEDB173AFDC214ECA95A836FA7C")), // Q
params);
@@ -430,7 +434,7 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d
params);
- SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335")));
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335")));
byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
@@ -457,7 +461,7 @@ public class ECTest
+ " got : " + sig[1]);
}
- // Verify the signature
+ // Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q
params);
@@ -469,6 +473,60 @@ public class ECTest
}
}
+ private void testECDSAP256sha3(int size, BigInteger s)
+ {
+ X9ECParameters p = NISTNamedCurves.getByName("P-256");
+ ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH());
+ ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+ new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d
+ params);
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335")));
+
+ byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
+
+ DSADigestSigner dsa = new DSADigestSigner(new ECDSASigner(), new SHA3Digest(size));
+
+ dsa.init(true, new ParametersWithRandom(priKey, k));
+
+ dsa.update(M, 0, M.length);
+
+ byte[] encSig = dsa.generateSignature();
+
+ ASN1Sequence sig = ASN1Sequence.getInstance(encSig);
+
+ BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384");
+
+ BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue();
+ if (!r.equals(sigR))
+ {
+ fail("r component wrong." + Strings.lineSeparator()
+ + " expecting: " + r.toString(16) + Strings.lineSeparator()
+ + " got : " + sigR.toString(16));
+ }
+
+ BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue();
+ if (!s.equals(sigS))
+ {
+ fail("s component wrong." + Strings.lineSeparator()
+ + " expecting: " + s.toString(16) + Strings.lineSeparator()
+ + " got : " + sigS.toString(16));
+ }
+
+ // Verify the signature
+ ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+ params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q
+ params);
+
+ dsa.init(false, pubKey);
+
+ dsa.update(M, 0, M.length);
+
+ if (!dsa.verifySignature(encSig))
+ {
+ fail("signature fails");
+ }
+ }
+
private void testECDSAP224OneByteOver()
{
X9ECParameters p = NISTNamedCurves.getByName("P-224");
@@ -476,7 +534,7 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d
params);
- SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79FF");
@@ -503,7 +561,7 @@ public class ECTest
+ " got : " + sig[1]);
}
- // Verify the signature
+ // Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q
params);
@@ -523,7 +581,7 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("617573726813476282316253885608633222275541026607493641741273231656161177732180358888434629562647985511298272498852936680947729040673640492310550142822667389"), // d
params);
- SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913")));
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913")));
byte[] M = Hex.decode("6893B64BD3A9615C39C3E62DDD269C2BAAF1D85915526083183CE14C2E883B48B193607C1ED871852C9DF9C3147B574DC1526C55DE1FE263A676346A20028A66");
@@ -550,7 +608,7 @@ public class ECTest
+ " got : " + sig[1]);
}
- // Verify the signature
+ // Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
params.getCurve().decodePoint(Hex.decode("020145E221AB9F71C5FE740D8D2B94939A09E2816E2167A7D058125A06A80C014F553E8D6764B048FB6F2B687CEC72F39738F223D4CE6AFCBFF2E34774AA5D3C342CB3")), // Q
params);
@@ -571,8 +629,8 @@ public class ECTest
BigInteger s = new BigInteger("144940322424411242416373536877786566515839911620497068645600824084578597");
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
-
- SecureRandom k = new FixedSecureRandom(kData);
+
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783");
BigInteger h = BigInteger.valueOf(4);
@@ -592,29 +650,29 @@ public class ECTest
ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
params);
-
+
ECDSASigner ecdsa = new ECDSASigner();
ParametersWithRandom param = new ParametersWithRandom(priKey, k);
-
+
ecdsa.init(true, param);
-
+
byte[] message = new BigInteger("968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517").toByteArray();
BigInteger[] sig = ecdsa.generateSignature(message);
-
+
if (!r.equals(sig[0]))
{
fail("r component wrong." + Strings.lineSeparator()
+ " expecting: " + r + Strings.lineSeparator()
+ " got : " + sig[0]);
}
-
+
if (!s.equals(sig[1]))
{
fail("s component wrong." + Strings.lineSeparator()
+ " expecting: " + s + Strings.lineSeparator()
+ " got : " + sig[1]);
}
-
+
// Verify the signature
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
@@ -647,15 +705,15 @@ public class ECTest
curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
n);
- ECKeyPairGenerator pGen = new ECKeyPairGenerator();
- ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
- params,
- random);
+ ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+ ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+ params,
+ random);
pGen.init(genParam);
- AsymmetricCipherKeyPair pair = pGen.generateKeyPair();
-
+ AsymmetricCipherKeyPair pair = pGen.generateKeyPair();
+
ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random);
ECDSASigner ecdsa = new ECDSASigner();
@@ -693,27 +751,27 @@ public class ECTest
curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
n);
- ECKeyPairGenerator pGen = new ECKeyPairGenerator();
- ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
- params,
- random);
+ ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+ ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+ params,
+ random);
pGen.init(genParam);
- AsymmetricCipherKeyPair p1 = pGen.generateKeyPair();
- AsymmetricCipherKeyPair p2 = pGen.generateKeyPair();
-
+ AsymmetricCipherKeyPair p1 = pGen.generateKeyPair();
+ AsymmetricCipherKeyPair p2 = pGen.generateKeyPair();
+
//
// two way
//
- BasicAgreement e1 = new ECDHBasicAgreement();
- BasicAgreement e2 = new ECDHBasicAgreement();
+ BasicAgreement e1 = new ECDHBasicAgreement();
+ BasicAgreement e2 = new ECDHBasicAgreement();
e1.init(p1.getPrivate());
e2.init(p2.getPrivate());
- BigInteger k1 = e1.calculateAgreement(p2.getPublic());
- BigInteger k2 = e2.calculateAgreement(p1.getPublic());
+ BigInteger k1 = e1.calculateAgreement(p2.getPublic());
+ BigInteger k2 = e2.calculateAgreement(p1.getPublic());
if (!k1.equals(k2))
{
@@ -738,157 +796,157 @@ public class ECTest
}
}
- private void testECMQVTestVector1()
- {
- // Test Vector from GEC-2
-
- X9ECParameters x9 = SECNamedCurves.getByName("secp160r1");
- ECDomainParameters p = new ECDomainParameters(
- x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
-
- AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("0251B4496FECC406ED0E75A24A3C03206251419DC0")), p),
- new ECPrivateKeyParameters(
- new BigInteger("AA374FFC3CE144E6B073307972CB6D57B2A4E982", 16), p));
-
- AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("03D99CE4D8BF52FA20BD21A962C6556B0F71F4CA1F")), p),
- new ECPrivateKeyParameters(
- new BigInteger("149EC7EA3A220A887619B3F9E5B4CA51C7D1779C", 16), p));
-
- AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("0349B41E0E9C0369C2328739D90F63D56707C6E5BC")), p),
- new ECPrivateKeyParameters(
- new BigInteger("45FB58A92A17AD4B15101C66E74F277E2B460866", 16), p));
-
- AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("02706E5D6E1F640C6E9C804E75DBC14521B1E5F3B5")), p),
- new ECPrivateKeyParameters(
- new BigInteger("18C13FCED9EADF884F7C595C8CB565DEFD0CB41E", 16), p));
-
- BigInteger x = calculateAgreement(U1, U2, V1, V2);
-
- if (x == null
- || !x.equals(new BigInteger("5A6955CEFDB4E43255FB7FCF718611E4DF8E05AC", 16)))
- {
- fail("MQV Test Vector #1 agreement failed");
- }
- }
-
- private void testECMQVTestVector2()
- {
- // Test Vector from GEC-2
-
- X9ECParameters x9 = SECNamedCurves.getByName("sect163k1");
- ECDomainParameters p = new ECDomainParameters(
- x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
-
- AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("03037D529FA37E42195F10111127FFB2BB38644806BC")), p),
- new ECPrivateKeyParameters(
- new BigInteger("03A41434AA99C2EF40C8495B2ED9739CB2155A1E0D", 16), p));
-
- AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("02015198E74BC2F1E5C9A62B80248DF0D62B9ADF8429")), p),
- new ECPrivateKeyParameters(
- new BigInteger("032FC4C61A8211E6A7C4B8B0C03CF35F7CF20DBD52", 16), p));
-
- AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("03072783FAAB9549002B4F13140B88132D1C75B3886C")), p),
- new ECPrivateKeyParameters(
- new BigInteger("57E8A78E842BF4ACD5C315AA0569DB1703541D96", 16), p));
-
- AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
- new ECPublicKeyParameters(
- p.getCurve().decodePoint(Hex.decode("03067E3AEA3510D69E8EDD19CB2A703DDC6CF5E56E32")), p),
- new ECPrivateKeyParameters(
- new BigInteger("02BD198B83A667A8D908EA1E6F90FD5C6D695DE94F", 16), p));
-
- BigInteger x = calculateAgreement(U1, U2, V1, V2);
-
- if (x == null
- || !x.equals(new BigInteger("038359FFD30C0D5FC1E6154F483B73D43E5CF2B503", 16)))
- {
- fail("MQV Test Vector #2 agreement failed");
- }
- }
-
- private void testECMQVRandom()
- {
- SecureRandom random = new SecureRandom();
-
- BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
-
- ECCurve.Fp curve = new ECCurve.Fp(
- new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
- new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
- new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
- n, ECConstants.ONE);
-
- ECDomainParameters parameters = new ECDomainParameters(
- curve,
- curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
- n);
-
- ECKeyPairGenerator pGen = new ECKeyPairGenerator();
-
- pGen.init(new ECKeyGenerationParameters(parameters, random));
-
-
- // Pre-established key pairs
- AsymmetricCipherKeyPair U1 = pGen.generateKeyPair();
- AsymmetricCipherKeyPair V1 = pGen.generateKeyPair();
-
- // Ephemeral key pairs
- AsymmetricCipherKeyPair U2 = pGen.generateKeyPair();
- AsymmetricCipherKeyPair V2 = pGen.generateKeyPair();
-
- BigInteger x = calculateAgreement(U1, U2, V1, V2);
-
- if (x == null)
- {
- fail("MQV Test Vector (random) agreement failed");
- }
- }
-
- private static BigInteger calculateAgreement(
- AsymmetricCipherKeyPair U1,
- AsymmetricCipherKeyPair U2,
- AsymmetricCipherKeyPair V1,
- AsymmetricCipherKeyPair V2)
- {
- ECMQVBasicAgreement u = new ECMQVBasicAgreement();
- u.init(new MQVPrivateParameters(
- (ECPrivateKeyParameters)U1.getPrivate(),
- (ECPrivateKeyParameters)U2.getPrivate(),
- (ECPublicKeyParameters)U2.getPublic()));
- BigInteger ux = u.calculateAgreement(new MQVPublicParameters(
- (ECPublicKeyParameters)V1.getPublic(),
- (ECPublicKeyParameters)V2.getPublic()));
-
- ECMQVBasicAgreement v = new ECMQVBasicAgreement();
- v.init(new MQVPrivateParameters(
- (ECPrivateKeyParameters)V1.getPrivate(),
- (ECPrivateKeyParameters)V2.getPrivate(),
- (ECPublicKeyParameters)V2.getPublic()));
- BigInteger vx = v.calculateAgreement(new MQVPublicParameters(
- (ECPublicKeyParameters)U1.getPublic(),
- (ECPublicKeyParameters)U2.getPublic()));
-
- if (ux.equals(vx))
- {
- return ux;
- }
-
- return null;
- }
+ private void testECMQVTestVector1()
+ {
+ // Test Vector from GEC-2
+
+ X9ECParameters x9 = SECNamedCurves.getByName("secp160r1");
+ ECDomainParameters p = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+
+ AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("0251B4496FECC406ED0E75A24A3C03206251419DC0")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("AA374FFC3CE144E6B073307972CB6D57B2A4E982", 16), p));
+
+ AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("03D99CE4D8BF52FA20BD21A962C6556B0F71F4CA1F")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("149EC7EA3A220A887619B3F9E5B4CA51C7D1779C", 16), p));
+
+ AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("0349B41E0E9C0369C2328739D90F63D56707C6E5BC")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("45FB58A92A17AD4B15101C66E74F277E2B460866", 16), p));
+
+ AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("02706E5D6E1F640C6E9C804E75DBC14521B1E5F3B5")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("18C13FCED9EADF884F7C595C8CB565DEFD0CB41E", 16), p));
+
+ BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+ if (x == null
+ || !x.equals(new BigInteger("5A6955CEFDB4E43255FB7FCF718611E4DF8E05AC", 16)))
+ {
+ fail("MQV Test Vector #1 agreement failed");
+ }
+ }
+
+ private void testECMQVTestVector2()
+ {
+ // Test Vector from GEC-2
+
+ X9ECParameters x9 = SECNamedCurves.getByName("sect163k1");
+ ECDomainParameters p = new ECDomainParameters(
+ x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+
+ AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("03037D529FA37E42195F10111127FFB2BB38644806BC")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("03A41434AA99C2EF40C8495B2ED9739CB2155A1E0D", 16), p));
+
+ AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("02015198E74BC2F1E5C9A62B80248DF0D62B9ADF8429")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("032FC4C61A8211E6A7C4B8B0C03CF35F7CF20DBD52", 16), p));
+
+ AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("03072783FAAB9549002B4F13140B88132D1C75B3886C")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("57E8A78E842BF4ACD5C315AA0569DB1703541D96", 16), p));
+
+ AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(
+ p.getCurve().decodePoint(Hex.decode("03067E3AEA3510D69E8EDD19CB2A703DDC6CF5E56E32")), p),
+ new ECPrivateKeyParameters(
+ new BigInteger("02BD198B83A667A8D908EA1E6F90FD5C6D695DE94F", 16), p));
+
+ BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+ if (x == null
+ || !x.equals(new BigInteger("038359FFD30C0D5FC1E6154F483B73D43E5CF2B503", 16)))
+ {
+ fail("MQV Test Vector #2 agreement failed");
+ }
+ }
+
+ private void testECMQVRandom()
+ {
+ SecureRandom random = new SecureRandom();
+
+ BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+ n, ECConstants.ONE);
+
+ ECDomainParameters parameters = new ECDomainParameters(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ n);
+
+ ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+
+ pGen.init(new ECKeyGenerationParameters(parameters, random));
+
+
+ // Pre-established key pairs
+ AsymmetricCipherKeyPair U1 = pGen.generateKeyPair();
+ AsymmetricCipherKeyPair V1 = pGen.generateKeyPair();
+
+ // Ephemeral key pairs
+ AsymmetricCipherKeyPair U2 = pGen.generateKeyPair();
+ AsymmetricCipherKeyPair V2 = pGen.generateKeyPair();
+
+ BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+ if (x == null)
+ {
+ fail("MQV Test Vector (random) agreement failed");
+ }
+ }
+
+ private static BigInteger calculateAgreement(
+ AsymmetricCipherKeyPair U1,
+ AsymmetricCipherKeyPair U2,
+ AsymmetricCipherKeyPair V1,
+ AsymmetricCipherKeyPair V2)
+ {
+ ECMQVBasicAgreement u = new ECMQVBasicAgreement();
+ u.init(new MQVPrivateParameters(
+ (ECPrivateKeyParameters)U1.getPrivate(),
+ (ECPrivateKeyParameters)U2.getPrivate(),
+ (ECPublicKeyParameters)U2.getPublic()));
+ BigInteger ux = u.calculateAgreement(new MQVPublicParameters(
+ (ECPublicKeyParameters)V1.getPublic(),
+ (ECPublicKeyParameters)V2.getPublic()));
+
+ ECMQVBasicAgreement v = new ECMQVBasicAgreement();
+ v.init(new MQVPrivateParameters(
+ (ECPrivateKeyParameters)V1.getPrivate(),
+ (ECPrivateKeyParameters)V2.getPrivate(),
+ (ECPublicKeyParameters)V2.getPublic()));
+ BigInteger vx = v.calculateAgreement(new MQVPublicParameters(
+ (ECPublicKeyParameters)U1.getPublic(),
+ (ECPublicKeyParameters)U2.getPublic()));
+
+ if (ux.equals(vx))
+ {
+ return ux;
+ }
+
+ return null;
+ }
public String getName()
{
@@ -911,7 +969,12 @@ public class ECTest
testECDSAP521sha512();
testECDSASecP224k1sha256();
testECDSA239bitBinaryAndLargeDigest();
-
+
+ testECDSAP256sha3(224, new BigInteger("84d7d8e68e405064109cd9fc3e3026d74d278aada14ce6b7a9dd0380c154dc94", 16));
+ testECDSAP256sha3(256, new BigInteger("99a43bdab4af989aaf2899079375642f2bae2dce05bcd8b72ec8c4a8d9a143f", 16));
+ testECDSAP256sha3(384, new BigInteger("aa27726509c37aaf601de6f7e01e11c19add99530c9848381c23365dc505b11a", 16));
+ testECDSAP256sha3(512, new BigInteger("f8306b57a1f5068bf12e53aabaae39e2658db39bc56747eaefb479995130ad16", 16));
+
testECMQVTestVector1();
testECMQVTestVector2();
testECMQVRandom();
@@ -919,7 +982,7 @@ public class ECTest
public static void main(
- String[] args)
+ String[] args)
{
runTest(new ECTest());
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GCMTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GCMTest.java
index b34cc4e9..16d83629 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/GCMTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GCMTest.java
@@ -4,7 +4,7 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.gcm.BasicGCMMultiplier;
@@ -309,7 +309,7 @@ public class GCMTest
protected BlockCipher createAESEngine()
{
- return new AESFastEngine();
+ return new AESEngine();
}
private void testExceptions() throws InvalidCipherTextException
@@ -338,12 +338,23 @@ public class GCMTest
// expected
}
- AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
+ try
+ {
+ AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
+
+ fail("no exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+
+ }
+
AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
- AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(
- new byte[16]), 128, new byte[16]));
- AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(
- new KeyParameter(new byte[16]), 128, new byte[16]));
+ // TODO: should probably come up with varients of these that don't trigger reuse exception
+// AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(
+// new byte[16]), 128, new byte[16]));
+// AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(
+// new KeyParameter(new byte[16]), 128, new byte[16]));
}
private void runTestCase(String[] testVector)
@@ -422,9 +433,16 @@ public class GCMTest
// Key reuse
AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters);
- encCipher.init(true, keyReuseParams);
- decCipher.init(false, keyReuseParams);
- checkTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T);
+
+ try
+ {
+ encCipher.init(true, keyReuseParams);
+ fail("no exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage()));
+ }
}
private GCMBlockCipher initCipher(GCMMultiplier m, boolean forEncryption, AEADParameters parameters)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GMacTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GMacTest.java
index 082aac61..6897ba64 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/GMacTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GMacTest.java
@@ -2,7 +2,7 @@ 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.engines.AESEngine;
import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
@@ -104,7 +104,7 @@ public class GMacTest extends SimpleTest
{
TestCase testCase = TEST_VECTORS[i];
- Mac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), testCase.getTag().length * 8);
+ Mac mac = new GMac(new GCMBlockCipher(new AESEngine()), testCase.getTag().length * 8);
CipherParameters key = new KeyParameter(testCase.getKey());
mac.init(new ParametersWithIV(key, testCase.getIv()));
@@ -122,7 +122,7 @@ public class GMacTest extends SimpleTest
{
try
{
- GMac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), size);
+ GMac mac = new GMac(new GCMBlockCipher(new AESEngine()), size);
mac.init(new ParametersWithIV(null, new byte[16]));
fail("Expected failure for illegal mac size " + size);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3410Test.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3410Test.java
index ea4a266b..58c9e35b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3410Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3410Test.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.test;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator;
import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator;
@@ -13,11 +16,9 @@ import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.NumberParsing;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
+import org.bouncycastle.util.test.TestRandomData;
import org.bouncycastle.util.test.TestResult;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
public class GOST3410Test
implements Test
{
@@ -38,9 +39,10 @@ public class GOST3410Test
return "GOST3410-TEST1-512";
}
- FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("00005EC900007341"), zeroTwo(64) });
- FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
- FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"));
+ FixedSecureRandom init_random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(Hex.decode("00005EC900007341")), new FixedSecureRandom.Data(zeroTwo(64)) });
+ FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
+ FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"));
BigInteger pValue = new BigInteger("EE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3", 16);
BigInteger qValue = new BigInteger("98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D", 16);
@@ -139,9 +141,10 @@ public class GOST3410Test
return "GOST3410-TEST2-512";
}
- FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("000000003DFC46F1000000000000000D"), zeroTwo(64) });
- FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
- FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"));
+ FixedSecureRandom init_random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(Hex.decode("000000003DFC46F1000000000000000D")), new FixedSecureRandom.Data(zeroTwo(64))});
+ FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
+ FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"));
BigInteger pValue = new BigInteger("8b08eb135af966aab39df294538580c7da26765d6d38d30cf1c06aae0d1228c3316a0e29198460fad2b19dc381c15c888c6dfd0fc2c565abb0bf1faff9518f85", 16);
BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411DigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411DigestTest.java
index 3bd0da29..d7928c51 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411DigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411DigestTest.java
@@ -6,6 +6,7 @@ import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
public class GOST3411DigestTest
@@ -55,7 +56,7 @@ public class GOST3411DigestTest
gMac.init(new KeyParameter(PKCS5S1ParametersGenerator.PKCS5PasswordToUTF8Bytes("1".toCharArray())));
- byte[] data = "fred".getBytes();
+ byte[] data = Strings.toByteArray("fred");
gMac.update(data, 0, data.length);
byte[] mac = new byte[gMac.getMacSize()];
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java
new file mode 100644
index 00000000..c96de7d1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.crypto.test;
+
+import java.util.ArrayList;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.GOST3411_2012_256Digest;
+import org.bouncycastle.crypto.digests.GOST3411_2012_512Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class GOST3411_2012_256DigestTest
+ extends DigestTest
+{
+ private static final String[] messages;
+
+ private static char[] M1 =
+ {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32
+ };
+
+ private static char[] M2=
+ {
+ 0xd1,0xe5,0x20,0xe2,0xe5,0xf2,0xf0,0xe8,0x2c,0x20,0xd1,0xf2,0xf0,0xe8,0xe1,0xee,0xe6,0xe8,0x20,0xe2,
+ 0xed,0xf3,0xf6,0xe8,0x2c,0x20,0xe2,0xe5,0xfe,0xf2,0xfa,0x20,0xf1,0x20,0xec,0xee,0xf0,0xff,0x20,0xf1,
+ 0xf2,0xf0,0xe5,0xeb,0xe0,0xec,0xe8,0x20,0xed,0xe0,0x20,0xf5,0xf0,0xe0,0xe1,0xf0,0xfb,0xff,0x20,0xef,
+ 0xeb,0xfa,0xea,0xfb,0x20,0xc8,0xe3,0xee,0xf0,0xe5,0xe2,0xfb
+ };
+
+ static
+ {
+
+ ArrayList<String> strList = new ArrayList<String>();
+
+ strList.add(new String(M1));
+ strList.add(new String(M2));
+
+ messages = new String[strList.size()];
+ for (int i = 0; i < strList.size(); i++)
+ {
+ messages[i] = (String)strList.get(i);
+ }
+ }
+
+ private static final String[] digests = {
+ "9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500",
+ "9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50"
+ };
+
+ GOST3411_2012_256DigestTest()
+ {
+ super(new GOST3411_2012_256Digest(), messages, digests);
+ }
+
+ public void performTest()
+ {
+ super.performTest();
+
+ HMac gMac = new HMac(new GOST3411_2012_256Digest());
+
+ gMac.init(new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")));
+
+ byte[] data = Hex.decode("0126bdb87800af214341456563780100");
+
+ gMac.update(data, 0, data.length);
+ byte[] mac = new byte[gMac.getMacSize()];
+
+ gMac.doFinal(mac, 0);
+
+ if (!Arrays.areEqual(Hex.decode("a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9"), mac))
+ {
+ fail("mac calculation failed.");
+ }
+ }
+
+ protected Digest cloneDigest(Digest digest)
+ {
+ return new GOST3411_2012_256Digest((GOST3411_2012_256Digest)digest);
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new GOST3411_2012_256DigestTest());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java
new file mode 100644
index 00000000..7701cf87
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.crypto.test;
+
+import java.util.ArrayList;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.GOST3411Digest;
+import org.bouncycastle.crypto.digests.GOST3411_2012_512Digest;
+import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class GOST3411_2012_512DigestTest
+ extends DigestTest
+{
+ private static final String[] messages;
+
+ private static char[] M1 =
+ {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32
+ };
+
+ private static char[] M2=
+ {
+ 0xd1,0xe5,0x20,0xe2,0xe5,0xf2,0xf0,0xe8,0x2c,0x20,0xd1,0xf2,0xf0,0xe8,0xe1,0xee,0xe6,0xe8,0x20,0xe2,
+ 0xed,0xf3,0xf6,0xe8,0x2c,0x20,0xe2,0xe5,0xfe,0xf2,0xfa,0x20,0xf1,0x20,0xec,0xee,0xf0,0xff,0x20,0xf1,
+ 0xf2,0xf0,0xe5,0xeb,0xe0,0xec,0xe8,0x20,0xed,0xe0,0x20,0xf5,0xf0,0xe0,0xe1,0xf0,0xfb,0xff,0x20,0xef,
+ 0xeb,0xfa,0xea,0xfb,0x20,0xc8,0xe3,0xee,0xf0,0xe5,0xe2,0xfb
+ };
+
+ static
+ {
+ ArrayList<String> strList = new ArrayList<String>();
+
+ strList.add(new String(M1));
+ strList.add(new String(M2));
+ messages = new String[strList.size()];
+ for (int i = 0; i < strList.size(); i++)
+ {
+ messages[i] = (String)strList.get(i);
+ }
+ }
+
+ private static final String[] digests = {
+ "1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48",
+ "1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28",
+ };
+
+ public GOST3411_2012_512DigestTest()
+ {
+ super(new GOST3411_2012_512Digest(), messages, digests);
+ }
+
+ public void performTest()
+ {
+ super.performTest();
+
+ HMac gMac = new HMac(new GOST3411_2012_512Digest());
+
+ gMac.init(new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")));
+
+ byte[] data = Hex.decode("0126bdb87800af214341456563780100");
+
+ gMac.update(data, 0, data.length);
+ byte[] mac = new byte[gMac.getMacSize()];
+
+ gMac.doFinal(mac, 0);
+
+ if (!Arrays.areEqual(Hex.decode("a59bab22ecae19c65fbde6e5f4e9f5d8549d31f037f9df9b905500e171923a773d5f1530f2ed7e964cb2eedc29e9ad2f3afe93b2814f79f5000ffc0366c251e6"), mac))
+ {
+ fail("mac calculation failed.");
+ }
+ }
+
+ protected Digest cloneDigest(Digest digest)
+ {
+ return new GOST3411_2012_512Digest((GOST3411_2012_512Digest)digest);
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new GOST3411_2012_512DigestTest());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/MD5DigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/MD5DigestTest.java
index ab9cab27..19d3735b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/MD5DigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/MD5DigestTest.java
@@ -34,6 +34,11 @@ public class MD5DigestTest
{
return new MD5Digest((MD5Digest)digest);
}
+
+ protected Digest cloneDigest(byte[] encodedState)
+ {
+ return new MD5Digest(encodedState);
+ }
public static void main(
String[] args)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/Poly1305Test.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/Poly1305Test.java
index 08ee8e10..f5f6869b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/Poly1305Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/Poly1305Test.java
@@ -2,13 +2,10 @@ package org.bouncycastle.crypto.test;
import java.security.SecureRandom;
-import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
import org.bouncycastle.crypto.macs.Poly1305;
import org.bouncycastle.crypto.params.KeyParameter;
@@ -24,51 +21,6 @@ public class Poly1305Test
{
private static final int MAXLEN = 1000;
- private static class KeyEngine
- implements BlockCipher
- {
-
- private byte[] key;
- private final int blockSize;
-
- public KeyEngine(int blockSize)
- {
- this.blockSize = blockSize;
- }
-
- public void init(boolean forEncryption, CipherParameters params)
- throws IllegalArgumentException
- {
- if (params instanceof KeyParameter)
- {
- this.key = ((KeyParameter)params).getKey();
- }
- }
-
- public String getAlgorithmName()
- {
- return "Key";
- }
-
- public int getBlockSize()
- {
- return blockSize;
- }
-
- public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
- throws DataLengthException,
- IllegalStateException
- {
- System.arraycopy(key, 0, out, outOff, key.length);
- return key.length;
- }
-
- public void reset()
- {
- }
-
- }
-
private static class TestCase
{
private final byte[] key;
@@ -88,55 +40,63 @@ public class Poly1305Test
}
private static TestCase[] CASES = {
- // Raw Poly1305
- // onetimeauth.c from nacl-20110221
- new TestCase("2539121d8e234e652d651fa4c8cff880eea6a7251c1e72916d11c2cb214d3c25", null,
- "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
- + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
- + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
- + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
- "f3ffc7703f9400e52a7dfb4b3d3305d9"),
-
- // Poly1305-AES
- // Loop 1 of test-poly1305aes from poly1305aes-20050218
- new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
- "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
- new TestCase("f795bd4a52e29ed713d313fa20e98dbcf795bd0a50e29e0710d3130a20e98d0c",
- "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
- new TestCase("e69dae0aab9f91c03a325dcc9436fa903ef49901c8e11c000430d90ad45e7603",
- "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
- new TestCase("85a4ea91a7de0b0d96eed0d4bf6ecf1cda4afc035087d90e503f8f0ea08c3e0d",
- "0b6ef7a0b8f8c738b0f8d5995415271f",
- "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
- "3c5a13adb18d31c64cc29972030c917d"),
- new TestCase(
- "25eb69bac5cdf7d6bfcee4d9d5507b82ca3c6a0da0a864024ca3090628c28e0d",
- "046772a4f0a8de92e4f0d628cdb04484",
- "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
- "fc5fb58dc65daf19b14d1d05da1064e8"),
-
- // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
- // expose Java unsigned integer problems
- new TestCase(
- "95cc0e44d0b79a8856afcae1bec4fe3c" + "01bcb20bfc8b6e03609ddd09f44b060f",
- null,
- "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
- + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
- + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
- + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
- + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
- + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
- + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
- + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
- + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
- + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
- + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
- + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
- new TestCase(
- "76fb3635a2dc92a1f768163ab12f2187" + "cd07fd0ef8c0be0afcbdb30af4af0009",
- null,
- "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
- "045be28cc52009f506bdbfabedacf0b4"),
+ // Raw Poly1305
+ // onetimeauth.c from nacl-20110221
+ new TestCase("eea6a7251c1e72916d11c2cb214d3c25" + "2539121d8e234e652d651fa4c8cff880", null,
+ "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
+ + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
+ + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
+ + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
+ "f3ffc7703f9400e52a7dfb4b3d3305d9"),
+ // Poly1305-AES
+ // Loop 1 of test-poly1305aes from poly1305aes-20050218
+ new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
+ new TestCase("f795bd0a50e29e0710d3130a20e98d0c" + "f795bd4a52e29ed713d313fa20e98dbc",
+ "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
+ new TestCase("3ef49901c8e11c000430d90ad45e7603" + "e69dae0aab9f91c03a325dcc9436fa90",
+ "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
+ new TestCase("da4afc035087d90e503f8f0ea08c3e0d" + "85a4ea91a7de0b0d96eed0d4bf6ecf1c",
+ "0b6ef7a0b8f8c738b0f8d5995415271f",
+ "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
+ "3c5a13adb18d31c64cc29972030c917d"),
+ new TestCase(
+ "ca3c6a0da0a864024ca3090628c28e0d" + "25eb69bac5cdf7d6bfcee4d9d5507b82",
+ "046772a4f0a8de92e4f0d628cdb04484",
+ "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
+ "fc5fb58dc65daf19b14d1d05da1064e8"),
+ // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
+ // expose Java unsigned integer problems
+ new TestCase(
+ "01bcb20bfc8b6e03609ddd09f44b060f" + "95cc0e44d0b79a8856afcae1bec4fe3c",
+ null,
+ "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
+ + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
+ + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
+ + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
+ + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
+ + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
+ + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
+ + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
+ + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
+ + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
+ + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
+ + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
+ new TestCase(
+ "cd07fd0ef8c0be0afcbdb30af4af0009" + "76fb3635a2dc92a1f768163ab12f2187",
+ null,
+ "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
+ "045be28cc52009f506bdbfabedacf0b4"),
+ // Test case from JIRA issue BJA-620
+ new TestCase(
+ "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff",
+ null,
+ "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff",
+ "c80cb43844f387946e5aa6085bdf67da")
+
};
@@ -156,6 +116,7 @@ public class Poly1305Test
}
testSequential();
testReset();
+ rfc7539Test();
}
private void testCase(int i)
@@ -167,12 +128,12 @@ public class Poly1305Test
if (tc.nonce == null)
{
// Raw Poly1305 test - don't do any transform on AES key part
- mac = new Poly1305(new KeyEngine(16));
- mac.init(new ParametersWithIV(new KeyParameter(tc.key), new byte[16]));
+ mac = new Poly1305();
+ mac.init(new KeyParameter(tc.key));
}
else
{
- mac = new Poly1305(new AESFastEngine());
+ mac = new Poly1305(new AESEngine());
mac.init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce));
}
mac.update(tc.message, 0, tc.message.length);
@@ -194,11 +155,11 @@ public class Poly1305Test
byte[] out = new byte[16];
int c = 0;
- final Mac mac = new Poly1305(new AESFastEngine());
+ final Mac mac = new Poly1305(new AESEngine());
for (int loop = 0; loop < 13; loop++)
{
len = 0;
- for (;;)
+ for (; ; )
{
c++;
mac.init(new ParametersWithIV(new KeyParameter(kr), n));
@@ -229,24 +190,36 @@ public class Poly1305Test
// System.out.printf("%d/%s\n", c, new String(Hex.encode(out)));
if (len >= MAXLEN)
+ {
break;
+ }
n[0] ^= loop;
for (int i = 0; i < 16; ++i)
+ {
n[i] ^= out[i];
+ }
if (len % 2 != 0)
+ {
for (int i = 0; i < 16; ++i)
+ {
kr[i] ^= out[i];
+ }
+ }
if (len % 3 != 0)
+ {
for (int i = 0; i < 16; ++i)
+ {
kr[i + 16] ^= out[i];
+ }
+ }
Poly1305KeyGenerator.clamp(kr);
m[len++] ^= out[0];
}
}
// Output after 13 loops as generated by poly1305 ref
- if (c != 13013 || !Arrays.areEqual(out, Hex.decode("c96f60a23701a5b0fd2016f58cbe4f7e")))
+ if (c != 13013 || !Arrays.areEqual(out, Hex.decode("89824ddf0816481051f4a82731cd56d5")))
{
- fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", new String(Hex.encode(out)));
+ fail("Sequential Poly1305 " + c, "89824ddf0816481051f4a82731cd56d5", new String(Hex.encode(out)));
}
}
@@ -261,7 +234,7 @@ public class Poly1305Test
byte[] out = new byte[16];
// Generate baseline
- Mac poly = new Poly1305(new AESFastEngine());
+ Mac poly = new Poly1305(new AESEngine());
poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
poly.update(m, 0, m.length);
@@ -307,14 +280,15 @@ public class Poly1305Test
gen.init(new KeyGenerationParameters(new SecureRandom(), 256));
byte[] k = gen.generateKey();
- Mac poly = new Poly1305(new AESFastEngine());
+ Mac poly = new Poly1305(new AESEngine());
poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
try
{
poly.init(new ParametersWithIV(new KeyParameter(k), new byte[15]));
fail("16 byte nonce required");
- } catch (IllegalArgumentException e)
+ }
+ catch (IllegalArgumentException e)
{
// Expected
}
@@ -325,11 +299,12 @@ public class Poly1305Test
System.arraycopy(k, 0, k2, 0, k2.length);
poly.init(new ParametersWithIV(new KeyParameter(k2), new byte[16]));
fail("32 byte key required");
- } catch (IllegalArgumentException e)
+ }
+ catch (IllegalArgumentException e)
{
// Expected
}
-
+ /*
try
{
k[19] = (byte)0xFF;
@@ -339,7 +314,7 @@ public class Poly1305Test
{
// Expected
}
-
+ */
}
private void testKeyGenerator()
@@ -356,7 +331,8 @@ public class Poly1305Test
try
{
Poly1305KeyGenerator.checkKey(k);
- } catch (IllegalArgumentException e)
+ }
+ catch (IllegalArgumentException e)
{
fail("Poly1305 key should be clamped on generation.");
}
@@ -368,7 +344,7 @@ public class Poly1305Test
{
fail("Poly1305 key should be clamped on generation.");
}
-
+ /*
try
{
k2[19] = (byte)0xff;
@@ -378,6 +354,154 @@ public class Poly1305Test
{
// Expected
}
+ */
+ }
+
+ public void rfc7539Test()
+ {
+ // From RFC 7539
+ byte[] keyMaterial = Hex.decode("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b");
+ byte[] data = Hex.decode("43727970746f677261706869 63 20 46 6f 72 75 6d 20 52 65 73 65 61 72 63 68 20 47 72 6f7570");
+ byte[] expected = Hex.decode("a8061dc1305136c6c22b8baf0c0127a9");
+
+ checkVector(keyMaterial, data, expected);
+
+ data = Hex.decode("48656c6c6f20776f726c6421");
+ keyMaterial = Hex.decode(
+ "746869732069732033322d6279746520" +
+ "6b657920666f7220506f6c7931333035");
+
+ checkVector(keyMaterial, data, Hex.decode("a6f745008f81c916a20dcc74eef2b2f0"));
+
+ // A.3 #1
+ keyMaterial = Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ data = Hex.decode(
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+ + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+ + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+ + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+ // A.3 #2
+ keyMaterial = Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0036 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e");
+
+ data = Hex.decode(
+ "41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74"
+ + "6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e"
+ + "64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72"
+ + "69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69"
+ + "63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72"
+ + "20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46"
+ + "20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20"
+ + "6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73"
+ + "74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69"
+ + "74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74"
+ + "20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69"
+ + "76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72"
+ + "65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74"
+ + "72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20"
+ + "73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75"
+ + "64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e"
+ + "74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69"
+ + "6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20"
+ + "77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63"
+ + "74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61"
+ + "74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e"
+ + "79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c"
+ + "20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65"
+ + "73 73 65 64 20 74 6f");
+
+ checkVector(keyMaterial, data, Hex.decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e"));
+
+ // A.3 #3
+ keyMaterial = Hex.decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0"));
+
+ // A.3 #4
+
+ keyMaterial = Hex.decode("1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0");
+
+ data = Hex.decode(
+ "27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61"
+ + "6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f"
+ + "76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64"
+ + "20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77"
+ + "61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77"
+ + "65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65"
+ + "73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20"
+ + "72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e");
+
+ checkVector(keyMaterial, data, Hex.decode("45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62"));
+
+ // A.3 #5
+ keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+ checkVector(keyMaterial, data, Hex.decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+ // A.3 #6
+ keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+ data = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+ // A.3 #7
+ keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFF0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+ // A.3 #8
+ keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFFB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01");
+
+ checkVector(keyMaterial, data, Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+ // A.3 #9
+ keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode("FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+ checkVector(keyMaterial, data, Hex.decode("FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"));
+
+ // A.3 #10
+ keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode(
+ "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+ + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+ + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+ + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00"));
+
+ // A.3 #11
+ keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+ data = Hex.decode(
+ "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+ + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+ + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+ checkVector(keyMaterial, data, Hex.decode("13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+ }
+
+ private void checkVector(byte[] keyMaterial, byte[] input, byte[] tag)
+ {
+ Poly1305 poly1305 = new Poly1305();
+
+ poly1305.init(new KeyParameter(keyMaterial));
+
+ poly1305.update(input, 0, input.length);
+
+ byte[] mac = new byte[poly1305.getMacSize()];
+
+ poly1305.doFinal(mac, 0);
+
+ if (!Arrays.areEqual(tag, mac))
+ {
+ fail("rfc7539", Hex.toHexString(tag), Hex.toHexString(mac));
+ }
}
public static void main(String[] args)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSABlindedTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSABlindedTest.java
index 7cb6e98a..c7efcae0 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSABlindedTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSABlindedTest.java
@@ -102,22 +102,22 @@ public class RSABlindedTest
private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+ checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect");
}
private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+ checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect");
}
private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+ checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect");
}
private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+ checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect");
}
private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java
index 605a2cac..ab1392d9 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java
@@ -1,15 +1,24 @@
package org.bouncycastle.crypto.test;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHA512tDigest;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.signers.RSADigestSigner;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.test.SimpleTest;
-import java.math.BigInteger;
-
public class RSADigestSignerTest
extends SimpleTest
{
@@ -32,14 +41,32 @@ public class RSADigestSignerTest
RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp);
RSAPrivateCrtKeyParameters rsaPrivate = new RSAPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv);
+ checkDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1);
+
+ checkDigest(rsaPublic, rsaPrivate, new SHA224Digest(), NISTObjectIdentifiers.id_sha224);
+ checkDigest(rsaPublic, rsaPrivate, new SHA256Digest(), NISTObjectIdentifiers.id_sha256);
+ checkDigest(rsaPublic, rsaPrivate, new SHA384Digest(), NISTObjectIdentifiers.id_sha384);
+ checkDigest(rsaPublic, rsaPrivate, new SHA512Digest(), NISTObjectIdentifiers.id_sha512);
+ checkDigest(rsaPublic, rsaPrivate, new SHA512tDigest(224), NISTObjectIdentifiers.id_sha512_224);
+ checkDigest(rsaPublic, rsaPrivate, new SHA512tDigest(256), NISTObjectIdentifiers.id_sha512_256);
+
+ checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(224), NISTObjectIdentifiers.id_sha3_224);
+ checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(256), NISTObjectIdentifiers.id_sha3_256);
+ checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(384), NISTObjectIdentifiers.id_sha3_384);
+ checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(512), NISTObjectIdentifiers.id_sha3_512);
+ }
+
+ private void checkDigest(RSAKeyParameters rsaPublic, RSAPrivateCrtKeyParameters rsaPrivate, Digest digest, ASN1ObjectIdentifier digOid)
+ throws Exception
+ {
byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 };
- RSADigestSigner signer = new RSADigestSigner(new SHA1Digest());
+ RSADigestSigner signer = new RSADigestSigner(digest);
signer.init(true, rsaPrivate);
signer.update(msg, 0, msg.length);
byte[] sig = signer.generateSignature();
- signer = new RSADigestSigner(new SHA1Digest(), X509ObjectIdentifiers.id_SHA1);
+ signer = new RSADigestSigner(digest, digOid);
signer.init(false, rsaPublic);
signer.update(msg, 0, msg.length);
if (!signer.verifySignature(sig))
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSATest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSATest.java
index 6624b810..54faa944 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/RSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/RSATest.java
@@ -6,11 +6,14 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.encodings.OAEPEncoding;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
@@ -21,14 +24,14 @@ import org.bouncycastle.util.test.SimpleTest;
public class RSATest
extends SimpleTest
{
- static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
- static BigInteger pubExp = new BigInteger("11", 16);
- static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
- static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16);
- static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16);
- static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16);
- static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16);
- static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16);
+ static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
+ static BigInteger pubExp = new BigInteger("11", 16);
+ static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
+ static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16);
+ static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16);
+ static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16);
+ static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16);
+ static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16);
static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
@@ -36,7 +39,7 @@ public class RSATest
// to check that we handling byte extension by big number correctly.
//
static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
-
+
static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
@@ -50,29 +53,30 @@ public class RSATest
private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- AsymmetricBlockCipher eng = new RSAEngine();
+ AsymmetricBlockCipher eng = new RSAEngine();
eng.init(true, privParameters);
-
+
byte[] data = null;
-
+ byte[] overSized = null;
+
try
{
- data = eng.processBlock(oversizedSig, 0, oversizedSig.length);
+ overSized = data = eng.processBlock(oversizedSig, 0, oversizedSig.length);
}
catch (Exception e)
{
fail("RSA: failed - exception " + e.toString(), e);
}
-
+
eng = new PKCS1Encoding(eng);
-
+
eng.init(false, pubParameters);
-
+
try
{
- data = eng.processBlock(data, 0, data.length);
-
+ data = eng.processBlock(overSized, 0, overSized.length);
+
fail("oversized signature block not recognised");
}
catch (InvalidCipherTextException e)
@@ -82,54 +86,67 @@ public class RSATest
fail("RSA: failed - exception " + e.toString(), e);
}
}
-
+
+ eng = new PKCS1Encoding(new RSAEngine(), Hex.decode("feedbeeffeedbeeffeedbeef"));
+ eng.init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+
+ try
+ {
+ data = eng.processBlock(overSized, 0, overSized.length);
+ isTrue("not fallback", Arrays.areEqual(Hex.decode("feedbeeffeedbeeffeedbeef"), data));
+ }
+ catch (InvalidCipherTextException e)
+ {
+ fail("RSA: failed - exception " + e.toString(), e);
+ }
+
//System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false");
-
- System.getProperties().put(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false");
+
+ System.getProperties().put(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY, "true");
eng = new PKCS1Encoding(new RSAEngine());
-
+
eng.init(false, pubParameters);
-
+
try
{
- data = eng.processBlock(data, 0, data.length);
+ data = eng.processBlock(overSized, 0, overSized.length);
}
catch (InvalidCipherTextException e)
{
fail("RSA: failed - exception " + e.toString(), e);
}
-
- System.getProperties().remove(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY);
+
+ System.getProperties().remove(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY);
}
-
+
private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+ checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect");
}
-
+
private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+ checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect");
}
private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+ checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect");
}
-
+
private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
- checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+ checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect");
}
private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage)
{
- AsymmetricBlockCipher eng = new RSAEngine();
+ AsymmetricBlockCipher eng = new RSAEngine();
eng.init(true, privParameters);
-
+
byte[] data = null;
-
+
try
{
data = eng.processBlock(inputData, 0, inputData.length);
@@ -138,15 +155,15 @@ public class RSATest
{
fail("RSA: failed - exception " + e.toString(), e);
}
-
+
eng = new PKCS1Encoding(eng);
-
+
eng.init(false, pubParameters);
-
+
try
{
data = eng.processBlock(data, 0, data.length);
-
+
fail("missing data block not recognised");
}
catch (InvalidCipherTextException e)
@@ -157,7 +174,7 @@ public class RSATest
}
}
}
-
+
private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters)
{
//
@@ -192,6 +209,28 @@ public class RSATest
{
fail("failed OAEP Test");
}
+
+ // check for oversized input
+ byte[] message = new byte[87];
+ RSAEngine rsaEngine = new RSAEngine();
+ AsymmetricBlockCipher cipher = new OAEPEncoding(rsaEngine, new SHA1Digest(), new SHA1Digest(), message);
+ cipher.init(true, new ParametersWithRandom(pubParameters, new SecureRandom()));
+
+ try
+ {
+ cipher.processBlock(message, 0, message.length);
+
+ fail("no exception thrown");
+ }
+ catch (DataLengthException e)
+ {
+ isTrue("message mismatch", "input data too long".equals(e.getMessage()));
+ }
+ catch (InvalidCipherTextException e)
+ {
+ fail("failed - exception " + e.toString(), e);
+ }
+
}
private void zeroBlockTest(CipherParameters encParameters, CipherParameters decParameters)
@@ -236,14 +275,14 @@ public class RSATest
public void performTest()
{
- RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp);
- RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
- byte[] data = Hex.decode(edgeInput);
+ RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp);
+ RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
+ byte[] data = Hex.decode(edgeInput);
//
// RAW
//
- AsymmetricBlockCipher eng = new RSAEngine();
+ AsymmetricBlockCipher eng = new RSAEngine();
eng.init(true, pubParameters);
@@ -307,7 +346,7 @@ public class RSATest
eng = new PKCS1Encoding(eng);
eng.init(true, pubParameters);
-
+
if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize())
{
fail("PKCS1 output block size incorrect");
@@ -324,20 +363,55 @@ public class RSATest
eng.init(false, privParameters);
+ byte[] plainData = null;
try
{
- data = eng.processBlock(data, 0, data.length);
+ plainData = eng.processBlock(data, 0, data.length);
}
catch (Exception e)
{
fail("failed - exception " + e.toString(), e);
}
- if (!input.equals(new String(Hex.encode(data))))
+ if (!input.equals(Hex.toHexString(plainData)))
{
fail("failed PKCS1 public/private Test");
}
+ PKCS1Encoding fEng = new PKCS1Encoding(new RSAEngine(), input.length() / 2);
+ fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+ try
+ {
+ plainData = fEng.processBlock(data, 0, data.length);
+ }
+ catch (Exception e)
+ {
+ fail("failed - exception " + e.toString(), e);
+ }
+
+ if (!input.equals(Hex.toHexString(plainData)))
+ {
+ fail("failed PKCS1 public/private fixed Test");
+ }
+
+ fEng = new PKCS1Encoding(new RSAEngine(), input.length());
+ fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+ try
+ {
+ data = fEng.processBlock(data, 0, data.length);
+ }
+ catch (Exception e)
+ {
+ fail("failed - exception " + e.toString(), e);
+ }
+
+ if (input.equals(Hex.toHexString(data)))
+ {
+ fail("failed to recognise incorrect plaint text length");
+ }
+
+ data = plainData;
+
//
// PKCS1 - private encrypt, public decrypt
//
@@ -347,7 +421,7 @@ public class RSATest
try
{
- data = eng.processBlock(data, 0, data.length);
+ data = eng.processBlock(plainData, 0, plainData.length);
}
catch (Exception e)
{
@@ -365,7 +439,7 @@ public class RSATest
fail("failed - exception " + e.toString(), e);
}
- if (!input.equals(new String(Hex.encode(data))))
+ if (!input.equals(Hex.toHexString(data)))
{
fail("failed PKCS1 private/public Test");
}
@@ -376,14 +450,14 @@ public class RSATest
//
// key generation test
//
- RSAKeyPairGenerator pGen = new RSAKeyPairGenerator();
- RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
- BigInteger.valueOf(0x11), new SecureRandom(), 768, 25);
+ RSAKeyPairGenerator pGen = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x11), new SecureRandom(), 768, 25);
pGen.init(genParam);
- AsymmetricCipherKeyPair pair = pGen.generateKeyPair();
-
+ AsymmetricCipherKeyPair pair = pGen.generateKeyPair();
+
eng = new RSAEngine();
if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768)
@@ -462,7 +536,7 @@ public class RSATest
for (int i = 0; i < 100; ++i)
{
pair = pGen.generateKeyPair();
- RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) pair.getPrivate();
+ RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters)pair.getPrivate();
BigInteger pqDiff = privKey.getP().subtract(privKey.getQ()).abs();
if (pqDiff.bitLength() < 42)
@@ -470,7 +544,7 @@ public class RSATest
fail("P and Q too close in RSA key pair");
}
}
-
+
testOAEP(pubParameters, privParameters);
testStrictPKCS1Length(pubParameters, privParameters);
testDudPKCS1Block(pubParameters, privParameters);
@@ -480,7 +554,7 @@ public class RSATest
try
{
- new RSAEngine().processBlock(new byte[]{ 1 }, 0, 1);
+ new RSAEngine().processBlock(new byte[]{1}, 0, 1);
fail("failed initialisation check");
}
catch (IllegalStateException e)
@@ -491,7 +565,7 @@ public class RSATest
public static void main(
- String[] args)
+ String[] args)
{
runTest(new RSATest());
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/RegressionTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/RegressionTest.java
index 021df8d5..9dbfe0e2 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -73,6 +73,8 @@ public class RegressionTest
new RIPEMD320DigestTest(),
new TigerDigestTest(),
new GOST3411DigestTest(),
+ new GOST3411_2012_256DigestTest(),
+ new GOST3411_2012_512DigestTest(),
new WhirlpoolDigestTest(),
new MD5HMacTest(),
new SHA1HMacTest(),
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/SHA3HMacTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/SHA3HMacTest.java
new file mode 100644
index 00000000..836cde39
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/SHA3HMacTest.java
@@ -0,0 +1,335 @@
+package org.bouncycastle.crypto.test;
+
+import org.bouncycastle.crypto.digests.SHA3Digest;
+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.SimpleTest;
+import org.bouncycastle.util.test.TestResult;
+
+/**
+ * SHA224 HMac Test
+ */
+public class SHA3HMacTest
+ extends SimpleTest
+{
+ final static String[][] sha3_224 =
+ {
+ {
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b",
+ "53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e",
+ "332cfd59347fdb8e576e77260be4aba2d6dc53117b3bfb52c6d18c04"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687 88898a8b 8c8d8e8f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3d626c 6f636b6c" +
+ "656e",
+ "d8b733bc f66c644a 12323d56 4e24dcf3" +
+ "fc75f231 f3b67968 359100c7"
+
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687 88898a8b 8c8d8e8f" +
+ "90919293 94959697 98999a9b 9c9d9e9f" +
+ "a0a1a2a3 a4a5a6a7 a8a9aaab",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3e626c 6f636b6c" +
+ "656e",
+ "078695ee cc227c63 6ad31d06 3a15dd05" +
+ "a7e819a6 6ec6d8de 1e193e59"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e2c20 77697468 20747275 6e636174" +
+ "65642074 6167",
+ "8569c54c bb00a9b7 8ff1b391 b0e5"
+ },
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7"
+ }
+ };
+
+ final static String[][] sha3_256 =
+ {
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e",
+ "4fe8e202 c4f058e8 dddc23d8 c34e4673" +
+ "43e23555 e24fc2f0 25d598f5 58f67205"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3d626c 6f636b6c" +
+ "656e",
+ "68b94e2e 538a9be4 103bebb5 aa016d47" +
+ "961d4d1a a9060613 13b557f8 af2c3faa"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687 88898a8b 8c8d8e8f" +
+ "90919293 94959697 98999a9b 9c9d9e9f" +
+ "a0a1a2a3 a4a5a6a7",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3e626c 6f636b6c" +
+ "656e",
+ "9bcf2c23 8e235c3c e88404e8 13bd2f3a" +
+ "97185ac6 f238c63d 6229a00b 07974258"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e2c20 77697468 20747275 6e636174" +
+ "65642074 6167",
+ "c8dc7148 d8c1423a a549105d afdf9cad"
+ },
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb"
+ }
+ };
+
+ final static String[][] sha3_384 = {
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e",
+ "d588a3c5 1f3f2d90 6e8298c1 199aa8ff" +
+ "62962181 27f6b38a 90b6afe2 c5617725" +
+ "bc99987f 79b22a55 7b6520db 710b7f42"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3d626c 6f636b6c" +
+ "656e",
+ "a27d24b5 92e8c8cb f6d4ce6f c5bf62d8" +
+ "fc98bf2d 486640d9 eb8099e2 4047837f" +
+ "5f3bffbe 92dcce90 b4ed5b1e 7e44fa90"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687 88898a8b 8c8d8e8f" +
+ "90919293 94959697",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3e626c 6f636b6c" +
+ "656e",
+ "e5ae4c73 9f455279 368ebf36 d4f5354c" +
+ "95aa184c 899d3870 e460ebc2 88ef1f94" +
+ "70053f73 f7c6da2a 71bcaec3 8ce7d6ac"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e2c20 77697468 20747275 6e636174" +
+ "65642074 6167",
+ "25f4bf53 606e91af 79d24a4b b1fd6aec" +
+ "d44414a3 0c8ebb0a"
+ },
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd"
+ }
+ };
+
+ final static String[][] sha3_512 = {
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e",
+ "4efd629d 6c71bf86 162658f2 9943b1c3" +
+ "08ce27cd fa6db0d9 c3ce8176 3f9cbce5" +
+ "f7ebe986 8031db1a 8f8eb7b6 b95e5c5e" +
+ "3f657a89 96c86a2f 6527e307 f0213196"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3d626c 6f636b6c" +
+ "656e",
+ "544e257e a2a3e5ea 19a590e6 a24b724c" +
+ "e6327757 723fe275 1b75bf00 7d80f6b3" +
+ "60744bf1 b7a88ea5 85f9765b 47911976" +
+ "d3191cf8 3c039f5f fab0d29c c9d9b6da"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f" +
+ "40414243 44454647 48494a4b 4c4d4e4f" +
+ "50515253 54555657 58595a5b 5c5d5e5f" +
+ "60616263 64656667 68696a6b 6c6d6e6f" +
+ "70717273 74757677 78797a7b 7c7d7e7f" +
+ "80818283 84858687",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3e626c 6f636b6c" +
+ "656e",
+ "5f464f5e 5b7848e3 885e49b2 c385f069" +
+ "4985d0e3 8966242d c4a5fe3f ea4b37d4" +
+ "6b65cece d5dcf594 38dd840b ab22269f" +
+ "0ba7febd b9fcf746 02a35666 b2a32915"
+ },
+ {
+ "00010203 04050607 08090a0b 0c0d0e0f" +
+ "10111213 14151617 18191a1b 1c1d1e1f" +
+ "20212223 24252627 28292a2b 2c2d2e2f" +
+ "30313233 34353637 38393a3b 3c3d3e3f",
+ "53616d70 6c65206d 65737361 67652066" +
+ "6f72206b 65796c65 6e3c626c 6f636b6c" +
+ "656e2c20 77697468 20747275 6e636174" +
+ "65642074 6167",
+ "7bb06d85 9257b25c e73ca700 df34c5cb" +
+ "ef5c898b ac91029e 0b27975d 4e526a08"
+ },
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e"
+ }
+ };
+
+ public String getName()
+ {
+ return "SHA3HMac";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ doTest(new HMac(new SHA3Digest(224)), sha3_224);
+ doTest(new HMac(new SHA3Digest(256)), sha3_256);
+ doTest(new HMac(new SHA3Digest(384)), sha3_384);
+ doTest(new HMac(new SHA3Digest(512)), sha3_512);
+ }
+
+ public void doTest(HMac hmac, String[][] data)
+ {
+ byte[] resBuf = new byte[hmac.getMacSize()];
+
+ for (int i = 0; i < data.length; i++)
+ {
+ byte[] m = Hex.decode(data[i][1]);
+
+ hmac.init(new KeyParameter(Hex.decode(data[i][0])));
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+
+ isTrue(hmac.getAlgorithmName() + " vector " + i + " failed got " + new String(Hex.encode(resBuf)), startsWith(resBuf, Hex.decode(data[i][2])));
+ }
+
+ //
+ // test reset
+ //
+ int vector = 0; // vector used for test
+ byte[] m = Hex.decode(data[vector][1]);
+
+ hmac.init(new KeyParameter(Hex.decode(data[vector][0])));
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+ hmac.reset();
+ hmac.update(m, 0, m.length);
+ hmac.doFinal(resBuf, 0);
+
+ isTrue(hmac.getAlgorithmName() + " reset with vector " + vector + " failed", Arrays.areEqual(resBuf, Hex.decode(data[vector][2])));
+ }
+
+ private static boolean startsWith(byte[] a, byte[] b)
+ {
+ if (a.length == b.length)
+ {
+ return Arrays.areEqual(a, b);
+ }
+
+ for (int i = 0; i != b.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static void main(
+ String[] args)
+ {
+ SHA3HMacTest test = new SHA3HMacTest();
+ TestResult result = test.perform();
+
+ System.out.println(result);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java
index a3ec2eba..d24af319 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java
@@ -214,6 +214,47 @@ public class SHAKEDigestTest
// System.err.println(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch");
// System.err.println(Hex.toHexString(output).toUpperCase());
}
+
+ if (partialBits == 0)
+ {
+ d = createDigest(v.getAlgorithm());
+
+ m = v.getMessage();
+
+ d.update(m, 0, m.length);
+ d.doOutput(output, 0, outLen / 2);
+ d.doOutput(output, outLen / 2, output.length - outLen / 2);
+
+ if (!Arrays.areEqual(expected, output))
+ {
+ fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended hash mismatch");
+ }
+
+ try
+ {
+ d.update((byte)0x01);
+ fail("no exception");
+ }
+ catch (IllegalStateException e)
+ {
+ isTrue("wrong exception", "attempt to absorb while squeezing".equals(e.getMessage()));
+ }
+
+ d = createDigest(v.getAlgorithm());
+
+ m = v.getMessage();
+
+ d.update(m, 0, m.length);
+ d.doOutput(output, 0, outLen / 2);
+ d.doFinal(output, outLen / 2, output.length - outLen / 2);
+
+ if (!Arrays.areEqual(expected, output))
+ {
+ fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended doFinal hash mismatch");
+ }
+
+ d.update((byte)0x01); // this should be okay as we've reset on doFinal()
+ }
}
private void skipUntil(BufferedReader r, String header) throws IOException
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java b/bcprov/src/main/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java
index 9cd33afc..596c2d49 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/test/cavp/CAVPReader.java
@@ -15,7 +15,7 @@ import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.macs.HMac;
@@ -109,7 +109,7 @@ public class CAVPReader
final Mac prf;
if (config.getProperty("PRF").matches("CMAC_AES\\d\\d\\d"))
{
- BlockCipher blockCipher = new AESFastEngine();
+ BlockCipher blockCipher = new AESEngine();
prf = new CMac(blockCipher);
}
else if (config.getProperty("PRF").matches("CMAC_TDES\\d"))
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsClient.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsClient.java
index 57c46f8b..2ad32597 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsClient.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsClient.java
@@ -87,9 +87,9 @@ public abstract class AbstractTlsClient
public boolean isFallback()
{
/*
- * draft-ietf-tls-downgrade-scsv-00 4. [..] is meant for use by clients that repeat a
- * connection attempt with a downgraded protocol in order to avoid interoperability problems
- * with legacy servers.
+ * RFC 7507 4. The TLS_FALLBACK_SCSV cipher suite value is meant for use by clients that
+ * repeat a connection attempt with a downgraded protocol (perform a "fallback retry") in
+ * order to work around interoperability problems with legacy servers.
*/
return false;
}
@@ -199,6 +199,11 @@ public abstract class AbstractTlsClient
{
checkForUnexpectedServerExtension(serverExtensions, TlsECCUtils.EXT_ec_point_formats);
}
+
+ /*
+ * RFC 7685 3. The server MUST NOT echo the extension.
+ */
+ checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_padding);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsServer.java
index 3c386802..8131c9fb 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AbstractTlsServer.java
@@ -115,10 +115,10 @@ public abstract class AbstractTlsServer
public void notifyFallback(boolean isFallback) throws IOException
{
/*
- * draft-ietf-tls-downgrade-scsv-00 3. If TLS_FALLBACK_SCSV appears in
- * ClientHello.cipher_suites and the highest protocol version supported by the server is
- * higher than the version indicated in ClientHello.client_version, the server MUST respond
- * with an inappropriate_fallback alert.
+ * RFC 7507 3. If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest
+ * protocol version supported by the server is higher than the version indicated in
+ * ClientHello.client_version, the server MUST respond with a fatal inappropriate_fallback
+ * alert [..].
*/
if (isFallback && getMaximumVersion().isLaterVersionOf(clientVersion))
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AlertDescription.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AlertDescription.java
index 3db267e2..9c294a90 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/AlertDescription.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/AlertDescription.java
@@ -215,13 +215,13 @@ public class AlertDescription
public static final short unknown_psk_identity = 115;
/*
- * draft-ietf-tls-downgrade-scsv-00
+ * RFC 7507
*/
/**
* If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version
* supported by the server is higher than the version indicated in ClientHello.client_version,
- * the server MUST respond with an inappropriate_fallback alert.
+ * the server MUST respond with a fatal inappropriate_fallback alert [..].
*/
public static final short inappropriate_fallback = 86;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/CertificateType.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/CertificateType.java
new file mode 100644
index 00000000..5dc503eb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/CertificateType.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.crypto.tls;
+
+/**
+ * RFC 6091
+ */
+public class CertificateType
+{
+ public static final short X509 = 0;
+ public static final short OpenPGP = 1;
+
+ /*
+ * RFC 7250
+ */
+ public static final short RawPublicKey = 2;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/Chacha20Poly1305.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/Chacha20Poly1305.java
index a82045bf..ad073557 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/Chacha20Poly1305.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/Chacha20Poly1305.java
@@ -3,20 +3,25 @@ package org.bouncycastle.crypto.tls;
import java.io.IOException;
import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.engines.ChaChaEngine;
-import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.engines.ChaCha7539Engine;
import org.bouncycastle.crypto.macs.Poly1305;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
+/**
+ * draft-ietf-tls-chacha20-poly1305-04
+ */
public class Chacha20Poly1305 implements TlsCipher
{
+ private static final byte[] ZEROES = new byte[15];
+
protected TlsContext context;
- protected ChaChaEngine encryptCipher;
- protected ChaChaEngine decryptCipher;
+ protected ChaCha7539Engine encryptCipher, decryptCipher;
+ protected byte[] encryptIV, decryptIV;
public Chacha20Poly1305(TlsContext context) throws IOException
{
@@ -27,30 +32,52 @@ public class Chacha20Poly1305 implements TlsCipher
this.context = context;
- byte[] key_block = TlsUtils.calculateKeyBlock(context, 64);
+ int cipherKeySize = 32;
+ // TODO SecurityParameters.fixed_iv_length
+ int fixed_iv_length = 12;
+ // TODO SecurityParameters.record_iv_length = 0
+
+ int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
+
+ byte[] key_block = TlsUtils.calculateKeyBlock(context, key_block_size);
- KeyParameter client_write_key = new KeyParameter(key_block, 0, 32);
- KeyParameter server_write_key = new KeyParameter(key_block, 32, 32);
+ int offset = 0;
- this.encryptCipher = new ChaChaEngine(20);
- this.decryptCipher = new ChaChaEngine(20);
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ byte[] client_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+ byte[] server_write_IV = Arrays.copyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+
+ if (offset != key_block_size)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ this.encryptCipher = new ChaCha7539Engine();
+ this.decryptCipher = new ChaCha7539Engine();
KeyParameter encryptKey, decryptKey;
if (context.isServer())
{
encryptKey = server_write_key;
decryptKey = client_write_key;
+ this.encryptIV = server_write_IV;
+ this.decryptIV = client_write_IV;
}
else
{
encryptKey = client_write_key;
decryptKey = server_write_key;
+ this.encryptIV = client_write_IV;
+ this.decryptIV = server_write_IV;
}
- byte[] dummyNonce = new byte[8];
-
- this.encryptCipher.init(true, new ParametersWithIV(encryptKey, dummyNonce));
- this.decryptCipher.init(false, new ParametersWithIV(decryptKey, dummyNonce));
+ this.encryptCipher.init(true, new ParametersWithIV(encryptKey, encryptIV));
+ this.decryptCipher.init(false, new ParametersWithIV(decryptKey, decryptIV));
}
public int getPlaintextLimit(int ciphertextLimit)
@@ -60,11 +87,9 @@ public class Chacha20Poly1305 implements TlsCipher
public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) throws IOException
{
- int ciphertextLength = len + 16;
+ KeyParameter macKey = initRecord(encryptCipher, true, seqNo, encryptIV);
- KeyParameter macKey = initRecordMAC(encryptCipher, true, seqNo);
-
- byte[] output = new byte[ciphertextLength];
+ byte[] output = new byte[len + 16];
encryptCipher.processBytes(plaintext, offset, len, output, 0);
byte[] additionalData = getAdditionalData(seqNo, type, len);
@@ -81,14 +106,13 @@ public class Chacha20Poly1305 implements TlsCipher
throw new TlsFatalAlert(AlertDescription.decode_error);
}
- int plaintextLength = len - 16;
+ KeyParameter macKey = initRecord(decryptCipher, false, seqNo, decryptIV);
- byte[] receivedMAC = Arrays.copyOfRange(ciphertext, offset + plaintextLength, offset + len);
-
- KeyParameter macKey = initRecordMAC(decryptCipher, false, seqNo);
+ int plaintextLength = len - 16;
byte[] additionalData = getAdditionalData(seqNo, type, plaintextLength);
byte[] calculatedMAC = calculateRecordMAC(macKey, additionalData, ciphertext, offset, plaintextLength);
+ byte[] receivedMAC = Arrays.copyOfRange(ciphertext, offset + plaintextLength, offset + len);
if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC))
{
@@ -97,24 +121,36 @@ public class Chacha20Poly1305 implements TlsCipher
byte[] output = new byte[plaintextLength];
decryptCipher.processBytes(ciphertext, offset, plaintextLength, output, 0);
-
return output;
}
- protected KeyParameter initRecordMAC(ChaChaEngine cipher, boolean forEncryption, long seqNo)
+ protected KeyParameter initRecord(StreamCipher cipher, boolean forEncryption, long seqNo, byte[] iv)
{
- byte[] nonce = new byte[8];
- TlsUtils.writeUint64(seqNo, nonce, 0);
-
+ byte[] nonce = calculateNonce(seqNo, iv);
cipher.init(forEncryption, new ParametersWithIV(null, nonce));
+ return generateRecordMACKey(cipher);
+ }
+ protected byte[] calculateNonce(long seqNo, byte[] iv)
+ {
+ byte[] nonce = new byte[12];
+ TlsUtils.writeUint64(seqNo, nonce, 4);
+
+ for (int i = 0; i < 12; ++i)
+ {
+ nonce[i] ^= iv[i];
+ }
+
+ return nonce;
+ }
+
+ protected KeyParameter generateRecordMACKey(StreamCipher cipher)
+ {
byte[] firstBlock = new byte[64];
cipher.processBytes(firstBlock, 0, firstBlock.length, firstBlock, 0);
- // NOTE: The BC implementation puts 'r' after 'k'
- System.arraycopy(firstBlock, 0, firstBlock, 32, 16);
- KeyParameter macKey = new KeyParameter(firstBlock, 16, 32);
- Poly1305KeyGenerator.clamp(macKey.getKey());
+ KeyParameter macKey = new KeyParameter(firstBlock, 0, 32);
+ Arrays.fill(firstBlock, (byte)0);
return macKey;
}
@@ -123,22 +159,33 @@ public class Chacha20Poly1305 implements TlsCipher
Mac mac = new Poly1305();
mac.init(macKey);
- updateRecordMAC(mac, additionalData, 0, additionalData.length);
- updateRecordMAC(mac, buf, off, len);
+ updateRecordMACText(mac, additionalData, 0, additionalData.length);
+ updateRecordMACText(mac, buf, off, len);
+ updateRecordMACLength(mac, additionalData.length);
+ updateRecordMACLength(mac, len);
byte[] output = new byte[mac.getMacSize()];
mac.doFinal(output, 0);
return output;
}
- protected void updateRecordMAC(Mac mac, byte[] buf, int off, int len)
+ protected void updateRecordMACLength(Mac mac, int len)
{
- mac.update(buf, off, len);
-
byte[] longLen = Pack.longToLittleEndian(len & 0xFFFFFFFFL);
mac.update(longLen, 0, longLen.length);
}
+ protected void updateRecordMACText(Mac mac, byte[] buf, int off, int len)
+ {
+ mac.update(buf, off, len);
+
+ int partial = len % 16;
+ if (partial != 0)
+ {
+ mac.update(ZEROES, 0, 16 - partial);
+ }
+ }
+
protected byte[] getAdditionalData(long seqNo, short type, int len) throws IOException
{
/*
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/CipherSuite.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/CipherSuite.java
index 9374cecf..7a9cb65c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/CipherSuite.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/CipherSuite.java
@@ -331,36 +331,36 @@ public class CipherSuite
public static final int TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF;
/*
- * draft-agl-tls-chacha20poly1305-04
+ * RFC 7507
*/
- public static final int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC13;
- public static final int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC14;
- public static final int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC15;
+ public static final int TLS_FALLBACK_SCSV = 0x5600;
/*
- * draft-josefsson-salsa20-tls-04
+ * draft-ietf-tls-chacha20-poly1305-04
*/
- public static final int TLS_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE410;
- public static final int TLS_RSA_WITH_SALSA20_SHA1 = 0xE411;
- public static final int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE412;
- public static final int TLS_ECDHE_RSA_WITH_SALSA20_SHA1 = 0xE413;
- public static final int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE414;
- public static final int TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1 = 0xE415;
- public static final int TLS_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE416;
- public static final int TLS_PSK_WITH_SALSA20_SHA1 = 0xE417;
- public static final int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE418;
- public static final int TLS_ECDHE_PSK_WITH_SALSA20_SHA1 = 0xE419;
- public static final int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41A;
- public static final int TLS_RSA_PSK_WITH_SALSA20_SHA1 = 0xE41B;
- public static final int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41C;
- public static final int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xE41D;
- public static final int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE41E;
- public static final int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xE41F;
+ public static final int DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8;
+ public static final int DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9;
+ public static final int DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAA;
+ public static final int DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAB;
+ public static final int DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC;
+ public static final int DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAD;
+ public static final int DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE;
/*
- * draft-ietf-tls-downgrade-scsv-00
+ * draft-zauner-tls-aes-ocb-04 (code points TBD)
*/
- public static final int TLS_FALLBACK_SCSV = 0x5600;
+ public static final int DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB = 0xFF00;
+ public static final int DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB = 0xFF01;
+ public static final int DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB = 0xFF02;
+ public static final int DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB = 0xFF03;
+ public static final int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB = 0xFF04;
+ public static final int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB = 0xFF05;
+ public static final int DRAFT_TLS_PSK_WITH_AES_128_OCB = 0xFF10;
+ public static final int DRAFT_TLS_PSK_WITH_AES_256_OCB = 0xFF11;
+ public static final int DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB = 0xFF12;
+ public static final int DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB = 0xFF13;
+ public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB = 0xFF14;
+ public static final int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB = 0xFF15;
public static boolean isSCSV(int cipherSuite)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
index bcbf2166..ef5a2504 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSClientProtocol.java
@@ -61,19 +61,29 @@ public class DTLSClientProtocol
}
catch (TlsFatalAlert fatalAlert)
{
- recordLayer.fail(fatalAlert.getAlertDescription());
+ abortClientHandshake(state, recordLayer, fatalAlert.getAlertDescription());
throw fatalAlert;
}
catch (IOException e)
{
- recordLayer.fail(AlertDescription.internal_error);
+ abortClientHandshake(state, recordLayer, AlertDescription.internal_error);
throw e;
}
catch (RuntimeException e)
{
- recordLayer.fail(AlertDescription.internal_error);
+ abortClientHandshake(state, recordLayer, AlertDescription.internal_error);
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
+ finally
+ {
+ securityParameters.clear();
+ }
+ }
+
+ protected void abortClientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription)
+ {
+ recordLayer.fail(alertDescription);
+ invalidateSession(state);
}
protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer)
@@ -446,10 +456,11 @@ public class DTLSClientProtocol
}
/*
- * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
- * containing a lower value than the latest (highest-valued) version supported by the
- * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
- * ClientHello.cipher_suites.
+ * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
+ * than the latest (highest-valued) version supported by the client, it SHOULD include
+ * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
+ * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
+ * to negotiate.)
*/
if (fallback && !Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReassembler.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReassembler.java
index c052dcd9..088dcd2e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReassembler.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReassembler.java
@@ -4,8 +4,11 @@ import java.util.Vector;
class DTLSReassembler
{
- private final short msg_type;
- private final byte[] body;
+ /*
+ * No 'final' modifiers so that it works in earlier JDKs
+ */
+ private short msg_type;
+ private byte[] body;
private Vector missing = new Vector();
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java
index 81c1f41a..2ce6b582 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java
@@ -243,7 +243,7 @@ class DTLSRecordLayer
if (alertLevel == AlertLevel.fatal)
{
- fail(alertDescription);
+ failed();
throw new TlsFatalAlert(alertDescription);
}
@@ -401,6 +401,16 @@ class DTLSRecordLayer
}
}
+ void failed()
+ {
+ if (!closed)
+ {
+ failed = true;
+
+ closeTransport();
+ }
+ }
+
void warn(short alertDescription, String message)
throws IOException
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
index 9218d190..9c0b8c15 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java
@@ -12,7 +12,10 @@ class DTLSReliableHandshake
{
private final static int MAX_RECEIVE_AHEAD = 10;
- private final DTLSRecordLayer recordLayer;
+ /*
+ * No 'final' modifiers so that it works in earlier JDKs
+ */
+ private DTLSRecordLayer recordLayer;
private TlsHandshakeHash handshakeHash;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
index e909f57b..7da59ef2 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java
@@ -66,19 +66,29 @@ public class DTLSServerProtocol
}
catch (TlsFatalAlert fatalAlert)
{
- recordLayer.fail(fatalAlert.getAlertDescription());
+ abortServerHandshake(state, recordLayer, fatalAlert.getAlertDescription());
throw fatalAlert;
}
catch (IOException e)
{
- recordLayer.fail(AlertDescription.internal_error);
+ abortServerHandshake(state, recordLayer, AlertDescription.internal_error);
throw e;
}
catch (RuntimeException e)
{
- recordLayer.fail(AlertDescription.internal_error);
+ abortServerHandshake(state, recordLayer, AlertDescription.internal_error);
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
+ finally
+ {
+ securityParameters.clear();
+ }
+ }
+
+ protected void abortServerHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription)
+ {
+ recordLayer.fail(alertDescription);
+ invalidateSession(state);
}
protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer)
@@ -432,6 +442,21 @@ public class DTLSServerProtocol
return buf.toByteArray();
}
+ protected void invalidateSession(ServerHandshakeState state)
+ {
+ if (state.sessionParameters != null)
+ {
+ state.sessionParameters.clear();
+ state.sessionParameters = null;
+ }
+
+ if (state.tlsSession != null)
+ {
+ state.tlsSession.invalidate();
+ state.tlsSession = null;
+ }
+ }
+
protected void notifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate)
throws IOException
{
@@ -660,6 +685,9 @@ public class DTLSServerProtocol
if (state.clientExtensions != null)
{
+ // NOTE: Validates the padding extension data, if present
+ TlsExtensionsUtils.getPaddingExtension(state.clientExtensions);
+
state.server.processClientExtensions(state.clientExtensions);
}
}
@@ -691,6 +719,9 @@ public class DTLSServerProtocol
{
TlsServer server = null;
TlsServerContextImpl serverContext = null;
+ TlsSession tlsSession = null;
+ SessionParameters sessionParameters = null;
+ SessionParameters.Builder sessionParametersBuilder = null;
int[] offeredCipherSuites = null;
short[] offeredCompressionMethods = null;
Hashtable clientExtensions = null;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java
index 14972146..3954cdbc 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DatagramTransport.java
@@ -2,6 +2,9 @@ package org.bouncycastle.crypto.tls;
import java.io.IOException;
+/**
+ * Base interface for an object sending and receiving DTLS data.
+ */
public interface DatagramTransport
{
int getReceiveLimit()
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java
index f3209434..f8a79934 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java
@@ -15,6 +15,7 @@ import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CCMBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.modes.OCBBlockCipher;
public class DefaultTlsCipherFactory
extends AbstractTlsCipherFactory
@@ -26,9 +27,6 @@ public class DefaultTlsCipherFactory
{
case EncryptionAlgorithm._3DES_EDE_CBC:
return createDESedeCipher(context, macAlgorithm);
- case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
- // NOTE: Ignores macAlgorithm
- return createChaCha20Poly1305(context);
case EncryptionAlgorithm.AES_128_CBC:
return createAESCipher(context, 16, macAlgorithm);
case EncryptionAlgorithm.AES_128_CCM:
@@ -37,20 +35,26 @@ public class DefaultTlsCipherFactory
case EncryptionAlgorithm.AES_128_CCM_8:
// NOTE: Ignores macAlgorithm
return createCipher_AES_CCM(context, 16, 8);
+ case EncryptionAlgorithm.AES_128_GCM:
+ // NOTE: Ignores macAlgorithm
+ return createCipher_AES_GCM(context, 16, 16);
+ case EncryptionAlgorithm.AES_128_OCB_TAGLEN96:
+ // NOTE: Ignores macAlgorithm
+ return createCipher_AES_OCB(context, 16, 12);
+ case EncryptionAlgorithm.AES_256_CBC:
+ return createAESCipher(context, 32, macAlgorithm);
case EncryptionAlgorithm.AES_256_CCM:
// NOTE: Ignores macAlgorithm
return createCipher_AES_CCM(context, 32, 16);
case EncryptionAlgorithm.AES_256_CCM_8:
// NOTE: Ignores macAlgorithm
return createCipher_AES_CCM(context, 32, 8);
- case EncryptionAlgorithm.AES_128_GCM:
- // NOTE: Ignores macAlgorithm
- return createCipher_AES_GCM(context, 16, 16);
- case EncryptionAlgorithm.AES_256_CBC:
- return createAESCipher(context, 32, macAlgorithm);
case EncryptionAlgorithm.AES_256_GCM:
// NOTE: Ignores macAlgorithm
return createCipher_AES_GCM(context, 32, 16);
+ case EncryptionAlgorithm.AES_256_OCB_TAGLEN96:
+ // NOTE: Ignores macAlgorithm
+ return createCipher_AES_OCB(context, 32, 12);
case EncryptionAlgorithm.CAMELLIA_128_CBC:
return createCamelliaCipher(context, 16, macAlgorithm);
case EncryptionAlgorithm.CAMELLIA_128_GCM:
@@ -61,14 +65,13 @@ public class DefaultTlsCipherFactory
case EncryptionAlgorithm.CAMELLIA_256_GCM:
// NOTE: Ignores macAlgorithm
return createCipher_Camellia_GCM(context, 32, 16);
- case EncryptionAlgorithm.ESTREAM_SALSA20:
- return createSalsa20Cipher(context, 12, 32, macAlgorithm);
+ case EncryptionAlgorithm.CHACHA20_POLY1305:
+ // NOTE: Ignores macAlgorithm
+ return createChaCha20Poly1305(context);
case EncryptionAlgorithm.NULL:
return createNullCipher(context, macAlgorithm);
case EncryptionAlgorithm.RC4_128:
return createRC4Cipher(context, 16, macAlgorithm);
- case EncryptionAlgorithm.SALSA20:
- return createSalsa20Cipher(context, 20, 32, macAlgorithm);
case EncryptionAlgorithm.SEED_CBC:
return createSEEDCipher(context, macAlgorithm);
default:
@@ -110,6 +113,13 @@ public class DefaultTlsCipherFactory
createAEADBlockCipher_AES_GCM(), cipherKeySize, macSize);
}
+ protected TlsAEADCipher createCipher_AES_OCB(TlsContext context, int cipherKeySize, int macSize)
+ throws IOException
+ {
+ return new TlsAEADCipher(context, createAEADBlockCipher_AES_OCB(),
+ createAEADBlockCipher_AES_OCB(), cipherKeySize, macSize, TlsAEADCipher.NONCE_DRAFT_CHACHA20_POLY1305);
+ }
+
protected TlsAEADCipher createCipher_Camellia_GCM(TlsContext context, int cipherKeySize, int macSize)
throws IOException
{
@@ -138,13 +148,6 @@ public class DefaultTlsCipherFactory
createHMACDigest(macAlgorithm), createHMACDigest(macAlgorithm), cipherKeySize, false);
}
- protected TlsStreamCipher createSalsa20Cipher(TlsContext context, int rounds, int cipherKeySize, int macAlgorithm)
- throws IOException
- {
- return new TlsStreamCipher(context, createSalsa20StreamCipher(rounds), createSalsa20StreamCipher(rounds),
- createHMACDigest(macAlgorithm), createHMACDigest(macAlgorithm), cipherKeySize, true);
- }
-
protected TlsBlockCipher createSEEDCipher(TlsContext context, int macAlgorithm)
throws IOException
{
@@ -178,6 +181,11 @@ public class DefaultTlsCipherFactory
return new GCMBlockCipher(createAESEngine());
}
+ protected AEADBlockCipher createAEADBlockCipher_AES_OCB()
+ {
+ return new OCBBlockCipher(createAESEngine(), createAESEngine());
+ }
+
protected AEADBlockCipher createAEADBlockCipher_Camellia_GCM()
{
// TODO Consider allowing custom configuration of multiplier
@@ -199,11 +207,6 @@ public class DefaultTlsCipherFactory
return new RC4Engine();
}
- protected StreamCipher createSalsa20StreamCipher(int rounds)
- {
- return new Salsa20Engine(rounds);
- }
-
protected BlockCipher createSEEDBlockCipher()
{
return new CBCBlockCipher(new SEEDEngine());
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsClient.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsClient.java
index d9da7691..e07a73f3 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsClient.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsClient.java
@@ -52,6 +52,7 @@ public abstract class DefaultTlsClient
case KeyExchangeAlgorithm.DHE_RSA:
return createDHEKeyExchange(keyExchangeAlgorithm);
+ case KeyExchangeAlgorithm.ECDH_anon:
case KeyExchangeAlgorithm.ECDH_ECDSA:
case KeyExchangeAlgorithm.ECDH_RSA:
return createECDHKeyExchange(keyExchangeAlgorithm);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java
index 3434c0e5..0287babf 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DefaultTlsServer.java
@@ -44,7 +44,7 @@ public abstract class DefaultTlsServer
protected DHParameters getDHParameters()
{
- return DHStandardGroups.rfc5114_2048_256;
+ return DHStandardGroups.rfc3526_2048;
}
protected int[] getCipherSuites()
@@ -79,11 +79,12 @@ public abstract class DefaultTlsServer
switch (keyExchangeAlgorithm)
{
- case KeyExchangeAlgorithm.DH_DSS:
case KeyExchangeAlgorithm.DHE_DSS:
return getDSASignerCredentials();
- case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_anon:
+ return null;
+
case KeyExchangeAlgorithm.ECDHE_ECDSA:
return getECDSASignerCredentials();
@@ -115,6 +116,7 @@ public abstract class DefaultTlsServer
case KeyExchangeAlgorithm.DHE_RSA:
return createDHEKeyExchange(keyExchangeAlgorithm);
+ case KeyExchangeAlgorithm.ECDH_anon:
case KeyExchangeAlgorithm.ECDH_ECDSA:
case KeyExchangeAlgorithm.ECDH_RSA:
return createECDHKeyExchange(keyExchangeAlgorithm);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java
index 2da2f76a..a45c3b96 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java
@@ -55,13 +55,14 @@ public class EncryptionAlgorithm
public static final int CAMELLIA_256_GCM = 20;
/*
- * draft-josefsson-salsa20-tls-04
+ * draft-ietf-tls-chacha20-poly1305-04
*/
- public static final int ESTREAM_SALSA20 = 100;
- public static final int SALSA20 = 101;
+ public static final int CHACHA20_POLY1305 = 102;
+ /** @deprecated */ public static final int AEAD_CHACHA20_POLY1305 = CHACHA20_POLY1305;
/*
- * draft-agl-tls-chacha20poly1305-04
+ * draft-zauner-tls-aes-ocb-04
*/
- public static final int AEAD_CHACHA20_POLY1305 = 102;
+ public static final int AES_128_OCB_TAGLEN96 = 103;
+ public static final int AES_256_OCB_TAGLEN96 = 104;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/ExtensionType.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/ExtensionType.java
index 09b8d46f..5bc9eeee 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/ExtensionType.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/ExtensionType.java
@@ -18,9 +18,26 @@ public class ExtensionType
public static final int user_mapping = 6;
/*
+ * RFC 5878
+ */
+ public static final int client_authz = 7;
+ public static final int server_authz = 8;
+
+ /*
+ * RFC RFC6091
+ */
+ public static final int cert_type = 9;
+
+ /*
+ * draft-ietf-tls-negotiated-ff-dhe-10
+ */
+ public static final int supported_groups = 10;
+
+ /*
* RFC 4492 5.1.
*/
- public static final int elliptic_curves = 10;
+ /** @deprecated Use {@link #supported_groups} instead */
+ public static final int elliptic_curves = supported_groups;
public static final int ec_point_formats = 11;
/*
@@ -44,14 +61,38 @@ public class ExtensionType
public static final int heartbeat = 15;
/*
+ * RFC 7301
+ */
+ public static final int application_layer_protocol_negotiation = 16;
+
+ /*
+ * RFC 6961
+ */
+ public static final int status_request_v2 = 17;
+
+ /*
+ * RFC 6962
+ */
+ public static final int signed_certificate_timestamp = 18;
+
+ /*
+ * RFC 7250
+ */
+ public static final int client_certificate_type = 19;
+ public static final int server_certificate_type = 20;
+
+ /*
+ * RFC 7685
+ */
+ public static final int padding = 21;
+
+ /*
* RFC 7366
*/
public static final int encrypt_then_mac = 22;
/*
- * draft-ietf-tls-session-hash-04
- *
- * NOTE: Early code-point assignment
+ * RFC 7627
*/
public static final int extended_master_secret = 23;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/HashAlgorithm.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/HashAlgorithm.java
index 2806e4b2..f68e3c73 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/HashAlgorithm.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/HashAlgorithm.java
@@ -40,4 +40,9 @@ public class HashAlgorithm
{
return getName(hashAlgorithm) + "(" + hashAlgorithm + ")";
}
+
+ public static boolean isPrivate(short hashAlgorithm)
+ {
+ return 224 <= hashAlgorithm && hashAlgorithm <= 255;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/NameType.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/NameType.java
index 9b0cd1b9..2310dc7b 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/NameType.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/NameType.java
@@ -6,4 +6,9 @@ public class NameType
* RFC 3546 3.1.
*/
public static final short host_name = 0;
+
+ public static boolean isValid(short nameType)
+ {
+ return nameType == host_name;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/OCSPStatusRequest.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/OCSPStatusRequest.java
index 473db23f..8eedbd65 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/OCSPStatusRequest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/OCSPStatusRequest.java
@@ -10,6 +10,7 @@ import java.util.Vector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ocsp.ResponderID;
import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.util.io.Streams;
/**
* RFC 3546 3.6
@@ -73,7 +74,7 @@ public class OCSPStatusRequest
}
TlsUtils.checkUint16(buf.size());
TlsUtils.writeUint16(buf.size(), output);
- buf.writeTo(output);
+ Streams.writeBufTo(buf, output);
}
if (requestExtensions == null)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java
index a1a07c1a..181e9824 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/PSKTlsServer.java
@@ -28,7 +28,7 @@ public class PSKTlsServer
protected DHParameters getDHParameters()
{
- return DHStandardGroups.rfc5114_2048_256;
+ return DHStandardGroups.rfc3526_2048;
}
protected int[] getCipherSuites()
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java
index 1faac960..1378d79f 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java
@@ -9,4 +9,10 @@ public class SRTPProtectionProfile
public static final int SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002;
public static final int SRTP_NULL_HMAC_SHA1_80 = 0x0005;
public static final int SRTP_NULL_HMAC_SHA1_32 = 0x0006;
+
+ /*
+ * RFC 7714 14.2.
+ */
+ public static final int SRTP_AEAD_AES_128_GCM = 0x0007;
+ public static final int SRTP_AEAD_AES_256_GCM = 0x0008;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/ServerNameList.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/ServerNameList.java
index 1dc81f01..7e0e3a9a 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/ServerNameList.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/ServerNameList.java
@@ -7,6 +7,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.io.Streams;
+
public class ServerNameList
{
protected Vector serverNameList;
@@ -16,9 +19,9 @@ public class ServerNameList
*/
public ServerNameList(Vector serverNameList)
{
- if (serverNameList == null || serverNameList.isEmpty())
+ if (serverNameList == null)
{
- throw new IllegalArgumentException("'serverNameList' must not be null or empty");
+ throw new IllegalArgumentException("'serverNameList' must not be null");
}
this.serverNameList = serverNameList;
@@ -43,15 +46,23 @@ public class ServerNameList
{
ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ short[] nameTypesSeen = new short[0];
for (int i = 0; i < serverNameList.size(); ++i)
{
ServerName entry = (ServerName)serverNameList.elementAt(i);
+
+ nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType());
+ if (nameTypesSeen == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
entry.encode(buf);
}
TlsUtils.checkUint16(buf.size());
TlsUtils.writeUint16(buf.size(), output);
- buf.writeTo(output);
+ Streams.writeBufTo(buf, output);
}
/**
@@ -74,13 +85,34 @@ public class ServerNameList
ByteArrayInputStream buf = new ByteArrayInputStream(data);
+ short[] nameTypesSeen = new short[0];
Vector server_name_list = new Vector();
while (buf.available() > 0)
{
ServerName entry = ServerName.parse(buf);
+
+ nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType());
+ if (nameTypesSeen == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
server_name_list.addElement(entry);
}
return new ServerNameList(server_name_list);
}
+
+ private static short[] checkNameType(short[] nameTypesSeen, short nameType)
+ {
+ /*
+ * RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same
+ * name_type.
+ */
+ if (!NameType.isValid(nameType) || Arrays.contains(nameTypesSeen, nameType))
+ {
+ return null;
+ }
+ return Arrays.append(nameTypesSeen, nameType);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAEADCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAEADCipher.java
index 39133e6a..0341e590 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAEADCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAEADCipher.java
@@ -10,31 +10,62 @@ import org.bouncycastle.util.Arrays;
public class TlsAEADCipher
implements TlsCipher
{
+ // TODO[draft-zauner-tls-aes-ocb-04] Apply data volume limit described in section 8.4
+
+ public static final int NONCE_RFC5288 = 1;
+
+ /*
+ * draft-zauner-tls-aes-ocb-04 specifies the nonce construction from draft-ietf-tls-chacha20-poly1305-04
+ */
+ static final int NONCE_DRAFT_CHACHA20_POLY1305 = 2;
+
protected TlsContext context;
protected int macSize;
- protected int nonce_explicit_length;
+ // TODO SecurityParameters.record_iv_length
+ protected int record_iv_length;
protected AEADBlockCipher encryptCipher;
protected AEADBlockCipher decryptCipher;
protected byte[] encryptImplicitNonce, decryptImplicitNonce;
+
+ protected int nonceMode;
public TlsAEADCipher(TlsContext context, AEADBlockCipher clientWriteCipher, AEADBlockCipher serverWriteCipher,
int cipherKeySize, int macSize) throws IOException
{
+ this(context, clientWriteCipher, serverWriteCipher, cipherKeySize, macSize, NONCE_RFC5288);
+ }
+
+ TlsAEADCipher(TlsContext context, AEADBlockCipher clientWriteCipher, AEADBlockCipher serverWriteCipher,
+ int cipherKeySize, int macSize, int nonceMode) throws IOException
+ {
if (!TlsUtils.isTLSv12(context))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
- this.context = context;
- this.macSize = macSize;
-
- // NOTE: Valid for RFC 5288/6655 ciphers but may need review for other AEAD ciphers
- this.nonce_explicit_length = 8;
+ this.nonceMode = nonceMode;
// TODO SecurityParameters.fixed_iv_length
- int fixed_iv_length = 4;
+ int fixed_iv_length;
+
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ fixed_iv_length = 4;
+ this.record_iv_length = 8;
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ fixed_iv_length = 12;
+ this.record_iv_length = 0;
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ this.context = context;
+ this.macSize = macSize;
int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
@@ -76,7 +107,7 @@ public class TlsAEADCipher
decryptKey = server_write_key;
}
- byte[] dummyNonce = new byte[fixed_iv_length + nonce_explicit_length];
+ byte[] dummyNonce = new byte[fixed_iv_length + record_iv_length];
this.encryptCipher.init(true, new AEADParameters(encryptKey, 8 * macSize, dummyNonce));
this.decryptCipher.init(false, new AEADParameters(decryptKey, 8 * macSize, dummyNonce));
@@ -85,29 +116,42 @@ public class TlsAEADCipher
public int getPlaintextLimit(int ciphertextLimit)
{
// TODO We ought to be able to ask the decryptCipher (independently of it's current state!)
- return ciphertextLimit - macSize - nonce_explicit_length;
+ return ciphertextLimit - macSize - record_iv_length;
}
public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len)
throws IOException
{
- byte[] nonce = new byte[this.encryptImplicitNonce.length + nonce_explicit_length];
- System.arraycopy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.length);
+ byte[] nonce = new byte[encryptImplicitNonce.length + record_iv_length];
- /*
- * RFC 5288/6655 The nonce_explicit MAY be the 64-bit sequence number.
- *
- * (May need review for other AEAD ciphers).
- */
- TlsUtils.writeUint64(seqNo, nonce, encryptImplicitNonce.length);
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ System.arraycopy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.length);
+ // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
+ TlsUtils.writeUint64(seqNo, nonce, encryptImplicitNonce.length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8);
+ for (int i = 0; i < encryptImplicitNonce.length; ++i)
+ {
+ nonce[i] ^= encryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
int plaintextOffset = offset;
int plaintextLength = len;
int ciphertextLength = encryptCipher.getOutputSize(plaintextLength);
- byte[] output = new byte[nonce_explicit_length + ciphertextLength];
- System.arraycopy(nonce, encryptImplicitNonce.length, output, 0, nonce_explicit_length);
- int outputPos = nonce_explicit_length;
+ byte[] output = new byte[record_iv_length + ciphertextLength];
+ if (record_iv_length != 0)
+ {
+ System.arraycopy(nonce, nonce.length - record_iv_length, output, 0, record_iv_length);
+ }
+ int outputPos = record_iv_length;
byte[] additionalData = getAdditionalData(seqNo, type, plaintextLength);
AEADParameters parameters = new AEADParameters(null, 8 * macSize, nonce, additionalData);
@@ -140,12 +184,27 @@ public class TlsAEADCipher
throw new TlsFatalAlert(AlertDescription.decode_error);
}
- byte[] nonce = new byte[this.decryptImplicitNonce.length + nonce_explicit_length];
- System.arraycopy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.length);
- System.arraycopy(ciphertext, offset, nonce, decryptImplicitNonce.length, nonce_explicit_length);
+ byte[] nonce = new byte[decryptImplicitNonce.length + record_iv_length];
+
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ System.arraycopy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.length);
+ System.arraycopy(ciphertext, offset, nonce, nonce.length - record_iv_length, record_iv_length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtils.writeUint64(seqNo, nonce, nonce.length - 8);
+ for (int i = 0; i < decryptImplicitNonce.length; ++i)
+ {
+ nonce[i] ^= decryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
- int ciphertextOffset = offset + nonce_explicit_length;
- int ciphertextLength = len - nonce_explicit_length;
+ int ciphertextOffset = offset + record_iv_length;
+ int ciphertextLength = len - record_iv_length;
int plaintextLength = decryptCipher.getOutputSize(ciphertextLength);
byte[] output = new byte[plaintextLength];
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java
index 62c2616e..f3796e83 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsAuthentication.java
@@ -2,6 +2,9 @@ package org.bouncycastle.crypto.tls;
import java.io.IOException;
+/**
+ * Base interface to provide TLS authentication credentials.
+ */
public interface TlsAuthentication
{
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java
index 00f246b4..6bce001c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClient.java
@@ -4,6 +4,9 @@ import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
+/**
+ * Interface describing a TLS client endpoint.
+ */
public interface TlsClient
extends TlsPeer
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java
index db9f15b7..3f481068 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientContext.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.tls;
+/**
+ * Marker interface to distinguish a TLS client context.
+ */
public interface TlsClientContext
extends TlsContext
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
index 23815952..2e5efdba 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java
@@ -900,10 +900,11 @@ public class TlsClientProtocol
}
/*
- * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
- * containing a lower value than the latest (highest-valued) version supported by the
- * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
- * ClientHello.cipher_suites.
+ * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
+ * than the latest (highest-valued) version supported by the client, it SHOULD include
+ * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
+ * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
+ * to negotiate.)
*/
if (fallback && !Arrays.contains(offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsDHUtils.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsDHUtils.java
index 2c2b9766..2c6a6929 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsDHUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsDHUtils.java
@@ -396,17 +396,18 @@ public class TlsDHUtils
case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
/*
- * draft-agl-tls-chacha20poly1305-04
+ * draft-ietf-tls-chacha20-poly1305-04
*/
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
/*
- * draft-josefsson-salsa20-tls-04
+ * draft-zauner-tls-aes-ocb-04
*/
- case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
return true;
@@ -417,7 +418,8 @@ public class TlsDHUtils
public static boolean areCompatibleParameters(DHParameters a, DHParameters b)
{
- return a.getP().equals(b.getP()) && a.getG().equals(b.getG());
+ return a.getP().equals(b.getP()) && a.getG().equals(b.getG())
+ && (a.getQ() == null || b.getQ() == null || a.getQ().equals(b.getQ()));
}
public static byte[] calculateDHBasicAgreement(DHPublicKeyParameters publicKey, DHPrivateKeyParameters privateKey)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECCUtils.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECCUtils.java
index de562ea2..0bcf8cba 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECCUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECCUtils.java
@@ -285,20 +285,21 @@ public class TlsECCUtils
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
/*
- * draft-agl-tls-chacha20poly1305-04
+ * draft-ietf-tls-chacha20-poly1305-04
*/
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
/*
- * draft-josefsson-salsa20-tls-04
+ * draft-zauner-tls-aes-ocb-04
*/
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
return true;
@@ -309,9 +310,7 @@ public class TlsECCUtils
public static boolean areOnSameCurve(ECDomainParameters a, ECDomainParameters b)
{
- // TODO Move to ECDomainParameters.equals() or other utility method?
- return a.getCurve().equals(b.getCurve()) && a.getG().equals(b.getG()) && a.getN().equals(b.getN())
- && a.getH().equals(b.getH());
+ return a != null && a.equals(b);
}
public static boolean isSupportedNamedCurve(int namedCurve)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java
index 3248e781..b2f3136f 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.tls;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -41,6 +42,7 @@ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
case KeyExchangeAlgorithm.ECDHE_ECDSA:
this.tlsSigner = new TlsECDSASigner();
break;
+ case KeyExchangeAlgorithm.ECDH_anon:
case KeyExchangeAlgorithm.ECDH_RSA:
case KeyExchangeAlgorithm.ECDH_ECDSA:
this.tlsSigner = null;
@@ -66,11 +68,18 @@ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
public void skipServerCredentials() throws IOException
{
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (keyExchange != KeyExchangeAlgorithm.ECDH_anon)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
}
public void processServerCertificate(Certificate serverCertificate) throws IOException
{
+ if (keyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
if (serverCertificate.isEmpty())
{
throw new TlsFatalAlert(AlertDescription.bad_certificate);
@@ -118,15 +127,49 @@ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
{
switch (keyExchange)
{
+ case KeyExchangeAlgorithm.ECDH_anon:
case KeyExchangeAlgorithm.ECDHE_ECDSA:
case KeyExchangeAlgorithm.ECDHE_RSA:
- case KeyExchangeAlgorithm.ECDH_anon:
return true;
default:
return false;
}
}
+ public byte[] generateServerKeyExchange()
+ throws IOException
+ {
+ if (!requiresServerKeyExchange())
+ {
+ return null;
+ }
+
+ // ECDH_anon is handled here, ECDHE_* in a subclass
+
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ this.ecAgreePrivateKey = TlsECCUtils.generateEphemeralServerKeyExchange(context.getSecureRandom(), namedCurves,
+ clientECPointFormats, buf);
+ return buf.toByteArray();
+ }
+
+ public void processServerKeyExchange(InputStream input)
+ throws IOException
+ {
+ if (!requiresServerKeyExchange())
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ // ECDH_anon is handled here, ECDHE_* in a subclass
+
+ ECDomainParameters curve_params = TlsECCUtils.readECParameters(namedCurves, clientECPointFormats, input);
+
+ byte[] point = TlsUtils.readOpaque8(input);
+
+ this.ecAgreePublicKey = TlsECCUtils.validateECPublicKey(TlsECCUtils.deserializeECPublicKey(
+ clientECPointFormats, curve_params, point));
+ }
+
public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException
{
/*
@@ -154,6 +197,11 @@ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
{
+ if (keyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
if (clientCredentials instanceof TlsAgreementCredentials)
{
// TODO Validate client cert has matching parameters (see 'TlsECCUtils.areOnSameCurve')?
@@ -181,6 +229,11 @@ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
public void processClientCertificate(Certificate clientCertificate) throws IOException
{
+ if (keyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
// TODO Extract the public key
// TODO If the certificate is 'fixed', take the public key as ecAgreeClientPublicKey
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java
index 8e50f57d..28309c57 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java
@@ -13,6 +13,7 @@ public class TlsExtensionsUtils
public static final Integer EXT_extended_master_secret = Integers.valueOf(ExtensionType.extended_master_secret);
public static final Integer EXT_heartbeat = Integers.valueOf(ExtensionType.heartbeat);
public static final Integer EXT_max_fragment_length = Integers.valueOf(ExtensionType.max_fragment_length);
+ public static final Integer EXT_padding = Integers.valueOf(ExtensionType.padding);
public static final Integer EXT_server_name = Integers.valueOf(ExtensionType.server_name);
public static final Integer EXT_status_request = Integers.valueOf(ExtensionType.status_request);
public static final Integer EXT_truncated_hmac = Integers.valueOf(ExtensionType.truncated_hmac);
@@ -44,6 +45,12 @@ public class TlsExtensionsUtils
extensions.put(EXT_max_fragment_length, createMaxFragmentLengthExtension(maxFragmentLength));
}
+ public static void addPaddingExtension(Hashtable extensions, int dataLength)
+ throws IOException
+ {
+ extensions.put(EXT_padding, createPaddingExtension(dataLength));
+ }
+
public static void addServerNameExtension(Hashtable extensions, ServerNameList serverNameList)
throws IOException
{
@@ -75,6 +82,13 @@ public class TlsExtensionsUtils
return extensionData == null ? -1 : readMaxFragmentLengthExtension(extensionData);
}
+ public static int getPaddingExtension(Hashtable extensions)
+ throws IOException
+ {
+ byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_padding);
+ return extensionData == null ? -1 : readPaddingExtension(extensionData);
+ }
+
public static ServerNameList getServerNameExtension(Hashtable extensions)
throws IOException
{
@@ -147,6 +161,13 @@ public class TlsExtensionsUtils
return extensionData;
}
+ public static byte[] createPaddingExtension(int dataLength)
+ throws IOException
+ {
+ TlsUtils.checkUint16(dataLength);
+ return new byte[dataLength];
+ }
+
public static byte[] createServerNameExtension(ServerNameList serverNameList)
throws IOException
{
@@ -240,6 +261,23 @@ public class TlsExtensionsUtils
return TlsUtils.readUint8(extensionData, 0);
}
+ public static int readPaddingExtension(byte[] extensionData)
+ throws IOException
+ {
+ if (extensionData == null)
+ {
+ throw new IllegalArgumentException("'extensionData' cannot be null");
+ }
+ for (int i = 0; i < extensionData.length; ++i)
+ {
+ if (extensionData[i] != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ return extensionData.length;
+ }
+
public static ServerNameList readServerNameExtension(byte[] extensionData)
throws IOException
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
index 906c5926..7b06a2e5 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java
@@ -45,6 +45,13 @@ public abstract class TlsProtocol
protected static final short CS_END = 16;
/*
+ * Different modes to handle the known IV weakness
+ */
+ protected static final short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting
+ protected static final short ADS_MODE_0_N = 1; // 0/n record splitting
+ protected static final short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only
+
+ /*
* Queues for data from some protocols.
*/
private ByteQueue applicationDataQueue = new ByteQueue();
@@ -64,7 +71,8 @@ public abstract class TlsProtocol
private volatile boolean closed = false;
private volatile boolean failedWithError = false;
private volatile boolean appDataReady = false;
- private volatile boolean splitApplicationDataRecords = true;
+ private volatile boolean appDataSplitEnabled = true;
+ private volatile int appDataSplitMode = ADS_MODE_1_Nsub1;
private byte[] expected_verify_data = null;
protected TlsSession tlsSession = null;
@@ -192,7 +200,7 @@ public abstract class TlsProtocol
{
this.recordStream.finaliseHandshake();
- this.splitApplicationDataRecords = !TlsUtils.isTLSv11(getContext());
+ this.appDataSplitEnabled = !TlsUtils.isTLSv11(getContext());
/*
* If this was an initial handshake, we are now ready to send and receive application data.
@@ -606,16 +614,27 @@ public abstract class TlsProtocol
* NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
*/
- if (this.splitApplicationDataRecords)
+ if (this.appDataSplitEnabled)
{
/*
* Protect against known IV attack!
*
* DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
*/
- safeWriteRecord(ContentType.application_data, buf, offset, 1);
- ++offset;
- --len;
+ switch (appDataSplitMode) {
+ case ADS_MODE_0_N_FIRSTONLY:
+ this.appDataSplitEnabled = false;
+ // fall through intended!
+ case ADS_MODE_0_N:
+ safeWriteRecord(ContentType.application_data, TlsUtils.EMPTY_BYTES, 0, 0);
+ break;
+ case ADS_MODE_1_Nsub1:
+ default:
+ safeWriteRecord(ContentType.application_data, buf, offset, 1);
+ ++offset;
+ --len;
+ break;
+ }
}
if (len > 0)
@@ -629,6 +648,15 @@ public abstract class TlsProtocol
}
}
+ protected void setAppDataSplitMode(int appDataSplitMode) {
+ if (appDataSplitMode < ADS_MODE_1_Nsub1 ||
+ appDataSplitMode > ADS_MODE_0_N_FIRSTONLY)
+ {
+ throw new IllegalArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode);
+ }
+ this.appDataSplitMode = appDataSplitMode;
+ }
+
protected void writeHandshakeMessage(byte[] buf, int off, int len) throws IOException
{
while (len > 0)
@@ -1206,6 +1234,21 @@ public abstract class TlsProtocol
{
ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ /*
+ * NOTE: There are reports of servers that don't accept a zero-length extension as the last
+ * one, so we write out any zero-length ones first as a best-effort workaround.
+ */
+ writeSelectedExtensions(buf, extensions, true);
+ writeSelectedExtensions(buf, extensions, false);
+
+ byte[] extBytes = buf.toByteArray();
+
+ TlsUtils.writeOpaque16(extBytes, output);
+ }
+
+ protected static void writeSelectedExtensions(OutputStream output, Hashtable extensions, boolean selectEmpty)
+ throws IOException
+ {
Enumeration keys = extensions.keys();
while (keys.hasMoreElements())
{
@@ -1213,14 +1256,13 @@ public abstract class TlsProtocol
int extension_type = key.intValue();
byte[] extension_data = (byte[])extensions.get(key);
- TlsUtils.checkUint16(extension_type);
- TlsUtils.writeUint16(extension_type, buf);
- TlsUtils.writeOpaque16(extension_data, buf);
+ if (selectEmpty == (extension_data.length == 0))
+ {
+ TlsUtils.checkUint16(extension_type);
+ TlsUtils.writeUint16(extension_type, output);
+ TlsUtils.writeOpaque16(extension_data, output);
+ }
}
-
- byte[] extBytes = buf.toByteArray();
-
- TlsUtils.writeOpaque16(extBytes, output);
}
protected static void writeSupplementalData(OutputStream output, Vector supplementalData)
@@ -1272,19 +1314,24 @@ public abstract class TlsProtocol
case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
@@ -1297,26 +1344,37 @@ public abstract class TlsProtocol
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java
index 2a9ae553..5e5883ae 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServer.java
@@ -4,6 +4,9 @@ import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
+/**
+ * Interface describing a TLS server endpoint.
+ */
public interface TlsServer
extends TlsPeer
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java
index 37a0c952..16988567 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerContext.java
@@ -1,5 +1,8 @@
package org.bouncycastle.crypto.tls;
+/**
+ * Marker interface to distinguish a TLS server context.
+ */
public interface TlsServerContext
extends TlsContext
{
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
index 512204cb..2923deeb 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java
@@ -640,6 +640,9 @@ public class TlsServerProtocol
if (clientExtensions != null)
{
+ // NOTE: Validates the padding extension data, if present
+ TlsExtensionsUtils.getPaddingExtension(clientExtensions);
+
tlsServer.processClientExtensions(clientExtensions);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsStreamCipher.java
index 4e2c2639..c86b6b56 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsStreamCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsStreamCipher.java
@@ -98,12 +98,6 @@ public class TlsStreamCipher
public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len)
{
- /*
- * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
- * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
- * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
- * of the 16-bit epoch with the 48-bit sequence number.
- */
if (usesNonce)
{
updateIV(encryptCipher, true, seqNo);
@@ -122,12 +116,6 @@ public class TlsStreamCipher
public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len)
throws IOException
{
- /*
- * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
- * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
- * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
- * of the 16-bit epoch with the 48-bit sequence number.
- */
if (usesNonce)
{
updateIV(decryptCipher, false, seqNo);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java
index e4671d89..a4021099 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java
@@ -449,7 +449,7 @@ public class TlsUtils
public static short readUint8(byte[] buf, int offset)
{
- return (short)buf[offset];
+ return (short)(buf[offset] & 0xff);
}
public static int readUint16(InputStream input)
@@ -461,7 +461,7 @@ public class TlsUtils
{
throw new EOFException();
}
- return i1 << 8 | i2;
+ return (i1 << 8) | i2;
}
public static int readUint16(byte[] buf, int offset)
@@ -503,7 +503,7 @@ public class TlsUtils
{
throw new EOFException();
}
- return ((i1 << 2) | (i2 << 16) | (i3 << 8) | i4) & 0xFFFFFFFFL;
+ return ((i1 << 24) | (i2 << 16) | (i3 << 8) | i4) & 0xFFFFFFFFL;
}
public static long readUint32(byte[] buf, int offset)
@@ -1340,7 +1340,12 @@ public class TlsUtils
SignatureAndHashAlgorithm signatureAndHashAlgorithm = (SignatureAndHashAlgorithm)
supportedSignatureAlgorithms.elementAt(i);
short hashAlgorithm = signatureAndHashAlgorithm.getHash();
- handshakeHash.trackHashAlgorithm(hashAlgorithm);
+
+ // TODO Support values in the "Reserved for Private Use" range
+ if (!HashAlgorithm.isPrivate(hashAlgorithm))
+ {
+ handshakeHash.trackHashAlgorithm(hashAlgorithm);
+ }
}
}
}
@@ -1403,15 +1408,17 @@ public class TlsUtils
{
switch (getEncryptionAlgorithm(ciphersuite))
{
- case EncryptionAlgorithm.AES_128_GCM:
- case EncryptionAlgorithm.AES_256_GCM:
case EncryptionAlgorithm.AES_128_CCM:
case EncryptionAlgorithm.AES_128_CCM_8:
+ case EncryptionAlgorithm.AES_128_GCM:
+ case EncryptionAlgorithm.AES_128_OCB_TAGLEN96:
case EncryptionAlgorithm.AES_256_CCM:
case EncryptionAlgorithm.AES_256_CCM_8:
+ case EncryptionAlgorithm.AES_256_GCM:
+ case EncryptionAlgorithm.AES_256_OCB_TAGLEN96:
case EncryptionAlgorithm.CAMELLIA_128_GCM:
case EncryptionAlgorithm.CAMELLIA_256_GCM:
- case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+ case EncryptionAlgorithm.CHACHA20_POLY1305:
return CipherType.aead;
case EncryptionAlgorithm.RC2_CBC_40:
@@ -1426,10 +1433,9 @@ public class TlsUtils
case EncryptionAlgorithm.SEED_CBC:
return CipherType.block;
+ case EncryptionAlgorithm.NULL:
case EncryptionAlgorithm.RC4_40:
case EncryptionAlgorithm.RC4_128:
- case EncryptionAlgorithm.ESTREAM_SALSA20:
- case EncryptionAlgorithm.SALSA20:
return CipherType.stream;
default:
@@ -1446,6 +1452,7 @@ public class TlsUtils
case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
@@ -1459,44 +1466,38 @@ public class TlsUtils
case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
return EncryptionAlgorithm._3DES_EDE_CBC;
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- return EncryptionAlgorithm.AEAD_CHACHA20_POLY1305;
-
case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
return EncryptionAlgorithm.AES_128_CBC;
- case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
- return EncryptionAlgorithm.AES_128_CBC;
-
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
@@ -1525,41 +1526,46 @@ public class TlsUtils
case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
return EncryptionAlgorithm.AES_128_GCM;
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ return EncryptionAlgorithm.AES_128_OCB_TAGLEN96;
+
case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
return EncryptionAlgorithm.AES_256_CBC;
- case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
- return EncryptionAlgorithm.AES_256_CBC;
-
- case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
- return EncryptionAlgorithm.AES_256_CBC;
-
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
@@ -1588,6 +1594,14 @@ public class TlsUtils
case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
return EncryptionAlgorithm.AES_256_GCM;
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ return EncryptionAlgorithm.AES_256_OCB_TAGLEN96;
+
case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
@@ -1662,20 +1676,20 @@ public class TlsUtils
case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
return EncryptionAlgorithm.CAMELLIA_256_GCM;
- case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
- return EncryptionAlgorithm.ESTREAM_SALSA20;
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ return EncryptionAlgorithm.CHACHA20_POLY1305;
case CipherSuite.TLS_RSA_WITH_NULL_MD5:
return EncryptionAlgorithm.NULL;
case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
@@ -1715,16 +1729,6 @@ public class TlsUtils
case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
return EncryptionAlgorithm.RC4_128;
- case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
- return EncryptionAlgorithm.SALSA20;
-
case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
@@ -1794,20 +1798,21 @@ public class TlsUtils
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
return KeyExchangeAlgorithm.DHE_PSK;
@@ -1818,23 +1823,30 @@ public class TlsUtils
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
return KeyExchangeAlgorithm.DHE_RSA;
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_anon;
+
case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
@@ -1871,53 +1883,54 @@ public class TlsUtils
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
return KeyExchangeAlgorithm.ECDHE_ECDSA;
case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
return KeyExchangeAlgorithm.ECDHE_PSK;
case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
return KeyExchangeAlgorithm.ECDHE_RSA;
case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
@@ -1926,21 +1939,22 @@ public class TlsUtils
case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
return KeyExchangeAlgorithm.PSK;
case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
@@ -1960,13 +1974,11 @@ public class TlsUtils
case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_RSA_WITH_NULL_MD5:
case CipherSuite.TLS_RSA_WITH_NULL_SHA:
case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
return KeyExchangeAlgorithm.RSA;
@@ -1981,12 +1993,11 @@ public class TlsUtils
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
return KeyExchangeAlgorithm.RSA_PSK;
case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
@@ -2027,19 +2038,24 @@ public class TlsUtils
case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
@@ -2051,31 +2067,42 @@ public class TlsUtils
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
@@ -2111,18 +2138,19 @@ public class TlsUtils
case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
- case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
- case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
@@ -2136,47 +2164,35 @@ public class TlsUtils
case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
- case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
- case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
case CipherSuite.TLS_RSA_WITH_NULL_SHA:
case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
@@ -2293,23 +2309,28 @@ public class TlsUtils
case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
@@ -2330,38 +2351,49 @@ public class TlsUtils
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java
index d9bddbcf..2a6b250d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java
@@ -72,11 +72,7 @@ public class MockDTLSClient
// return Arrays.concatenate(super.getCipherSuites(),
// new int[]
// {
-// CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-// CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
-// CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
-// CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
-// CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+// CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// });
// }
@@ -90,6 +86,7 @@ public class MockDTLSClient
* NOTE: If you are copying test code, do not blindly set these extensions in your own client.
*/
TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9);
+ TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getSecureRandom().nextInt(16));
TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions);
}
return clientExtensions;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java
index 7811ecf4..9e5544b3 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java
@@ -48,11 +48,7 @@ public class MockDTLSServer
return Arrays.concatenate(super.getCipherSuites(),
new int[]
{
- CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
- CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
- CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
- CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+ CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
});
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsClient.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsClient.java
index 0572317d..dc10410d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsClient.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsClient.java
@@ -8,6 +8,7 @@ import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.crypto.tls.AlertDescription;
import org.bouncycastle.crypto.tls.AlertLevel;
import org.bouncycastle.crypto.tls.CertificateRequest;
+import org.bouncycastle.crypto.tls.CipherSuite;
import org.bouncycastle.crypto.tls.ClientCertificateType;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.MaxFragmentLength;
@@ -62,11 +63,7 @@ class MockTlsClient
// return Arrays.concatenate(super.getCipherSuites(),
// new int[]
// {
-// CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-// CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
-// CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
-// CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
-// CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+// CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// });
// }
@@ -80,6 +77,7 @@ class MockTlsClient
* NOTE: If you are copying test code, do not blindly set these extensions in your own client.
*/
TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9);
+ TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getSecureRandom().nextInt(16));
TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions);
}
return clientExtensions;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsServer.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsServer.java
index 39bba1f6..f28a075e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsServer.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/MockTlsServer.java
@@ -48,11 +48,7 @@ class MockTlsServer
return Arrays.concatenate(super.getCipherSuites(),
new int[]
{
- CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
- CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
- CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
- CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+ CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
});
}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/package.html
new file mode 100644
index 00000000..ec6dbbc8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/test/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Example code and test classes for the lightweight TLS API.
+</body>
+</html>
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java
new file mode 100644
index 00000000..c19c3512
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.crypto.util;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHA512tDigest;
+
+/**
+ * Basic factory class for message digests.
+ */
+public final class DigestFactory
+{
+ public static Digest createMD5()
+ {
+ return new MD5Digest();
+ }
+
+ public static Digest createSHA1()
+ {
+ return new SHA1Digest();
+ }
+
+ public static Digest createSHA224()
+ {
+ return new SHA224Digest();
+ }
+
+ public static Digest createSHA256()
+ {
+ return new SHA256Digest();
+ }
+
+ public static Digest createSHA384()
+ {
+ return new SHA384Digest();
+ }
+
+ public static Digest createSHA512()
+ {
+ return new SHA512Digest();
+ }
+
+ public static Digest createSHA512_224()
+ {
+ return new SHA512tDigest(224);
+ }
+
+ public static Digest createSHA512_256()
+ {
+ return new SHA512tDigest(256);
+ }
+
+ public static Digest createSHA3_224()
+ {
+ return new SHA3Digest(224);
+ }
+
+ public static Digest createSHA3_256()
+ {
+ return new SHA3Digest(256);
+ }
+
+ public static Digest createSHA3_384()
+ {
+ return new SHA3Digest(384);
+ }
+
+ public static Digest createSHA3_512()
+ {
+ return new SHA3Digest(512);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
index da6ecbd7..be4f5e4f 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
@@ -28,10 +28,15 @@ import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
*/
public class PrivateKeyInfoFactory
{
+ private PrivateKeyInfoFactory()
+ {
+
+ }
+
/**
* Create a PrivateKeyInfo representation of a private key.
*
- * @param privateKey the SubjectPublicKeyInfo encoding
+ * @param privateKey the key to be encoded into the info object.
* @return the appropriate key parameter
* @throws java.io.IOException on an error encoding the key
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
index af7c3b1c..3e07106c 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -28,11 +28,16 @@ import org.bouncycastle.crypto.params.RSAKeyParameters;
*/
public class SubjectPublicKeyInfoFactory
{
+ private SubjectPublicKeyInfoFactory()
+ {
+
+ }
+
/**
* Create a SubjectPublicKeyInfo public key.
*
- * @param publicKey the SubjectPublicKeyInfo encoding
- * @return the appropriate key parameter
+ * @param publicKey the key to be encoded into the info object.
+ * @return a SubjectPublicKeyInfo representing the key.
* @throws java.io.IOException on an error encoding the key
*/
public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) throws IOException
diff --git a/bcprov/src/main/java/org/bouncycastle/iana/AEADAlgorithm.java b/bcprov/src/main/java/org/bouncycastle/iana/AEADAlgorithm.java
new file mode 100644
index 00000000..c289b6a3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/iana/AEADAlgorithm.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.iana;
+
+/**
+ * RFC 5116
+ */
+public class AEADAlgorithm
+{
+ public static final int AEAD_AES_128_GCM = 1;
+ public static final int AEAD_AES_256_GCM = 2;
+ public static final int AEAD_AES_128_CCM = 3;
+ public static final int AEAD_AES_256_CCM = 4;
+
+ /*
+ * RFC 5282
+ */
+ public static final int AEAD_AES_128_GCM_8 = 5;
+ public static final int AEAD_AES_256_GCM_8 = 6;
+ public static final int AEAD_AES_128_GCM_12 = 7;
+ public static final int AEAD_AES_256_GCM_12 = 8;
+ public static final int AEAD_AES_128_CCM_SHORT = 9;
+ public static final int AEAD_AES_256_CCM_SHORT = 10;
+ public static final int AEAD_AES_128_CCM_SHORT_8 = 11;
+ public static final int AEAD_AES_256_CCM_SHORT_8 = 12;
+ public static final int AEAD_AES_128_CCM_SHORT_12 = 13;
+ public static final int AEAD_AES_256_CCM_SHORT_12 = 14;
+
+ /*
+ * RFC 5297
+ */
+ public static final int AEAD_AES_SIV_CMAC_256 = 15;
+ public static final int AEAD_AES_SIV_CMAC_384 = 16;
+ public static final int AEAD_AES_SIV_CMAC_512 = 17;
+
+ /*
+ * RFC 6655
+ */
+ public static final int AEAD_AES_128_CCM_8 = 18;
+ public static final int AEAD_AES_256_CCM_8 = 19;
+
+ /*
+ * RFC 7253
+ */
+ public static final int AEAD_AES_128_OCB_TAGLEN128 = 20;
+ public static final int AEAD_AES_128_OCB_TAGLEN96 = 21;
+ public static final int AEAD_AES_128_OCB_TAGLEN64 = 22;
+ public static final int AEAD_AES_192_OCB_TAGLEN128 = 23;
+ public static final int AEAD_AES_192_OCB_TAGLEN96 = 24;
+ public static final int AEAD_AES_192_OCB_TAGLEN64 = 25;
+ public static final int AEAD_AES_256_OCB_TAGLEN128 = 26;
+ public static final int AEAD_AES_256_OCB_TAGLEN96 = 27;
+ public static final int AEAD_AES_256_OCB_TAGLEN64 = 28;
+
+ /*
+ * RFC 7539
+ */
+ public static final int AEAD_CHACHA20_POLY1305 = 29;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java b/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java
index db63ecdb..856b3e5b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java
@@ -29,6 +29,11 @@ public class PKCS12Key
*/
public PKCS12Key(char[] password, boolean useWrongZeroLengthConversion)
{
+ if (password == null)
+ {
+ password = new char[0];
+ }
+
this.password = new char[password.length];
this.useWrongZeroLengthConversion = useWrongZeroLengthConversion;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
index 7c6c57ea..badbfd14 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
@@ -38,19 +38,14 @@ public class DH
provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
provider.addAlgorithm("Cipher.IES", PREFIX + "IESCipher$IES");
- provider.addAlgorithm("Cipher.IESwithAES", PREFIX + "IESCipher$IESwithAES");
- provider.addAlgorithm("Cipher.IESWITHAES", PREFIX + "IESCipher$IESwithAES");
- provider.addAlgorithm("Cipher.IESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede");
+ provider.addAlgorithm("Cipher.IESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+ provider.addAlgorithm("Cipher.IESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+ provider.addAlgorithm("Cipher.IESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC");
provider.addAlgorithm("Cipher.DHIES", PREFIX + "IESCipher$IES");
- provider.addAlgorithm("Cipher.DHIESwithAES", PREFIX + "IESCipher$IESwithAES");
- provider.addAlgorithm("Cipher.DHIESWITHAES", PREFIX + "IESCipher$IESwithAES");
- provider.addAlgorithm("Cipher.DHIESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede");
-
- provider.addAlgorithm("Cipher.OLDDHIES", PREFIX + "IESCipher$OldIES");
- provider.addAlgorithm("Cipher.OLDDHIESwithAES", PREFIX + "IESCipher$OldIESwithAES");
- provider.addAlgorithm("Cipher.OLDDHIESWITHAES", PREFIX + "IESCipher$OldIESwithAES");
- provider.addAlgorithm("Cipher.OLDDHIESWITHDESEDE", PREFIX + "IESCipher$OldIESwithDESede");
+ provider.addAlgorithm("Cipher.DHIESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+ provider.addAlgorithm("Cipher.DHIESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+ provider.addAlgorithm("Cipher.DHIESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC");
registerOid(provider, PKCSObjectIdentifiers.dhKeyAgreement, "DH", new KeyFactorySpi());
registerOid(provider, X9ObjectIdentifiers.dhpublicnumber, "DH", new KeyFactorySpi());
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
index 2efffbf4..1bdc9941 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
@@ -39,11 +39,27 @@ public class DSA
provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
+ provider.addAlgorithm("Signature.DDSA", PREFIX + "DSASigner$detDSA");
+ provider.addAlgorithm("Signature.SHA1WITHDDSA", PREFIX + "DSASigner$detDSA");
+ provider.addAlgorithm("Signature.SHA224WITHDDSA", PREFIX + "DSASigner$detDSA224");
+ provider.addAlgorithm("Signature.SHA256WITHDDSA", PREFIX + "DSASigner$detDSA256");
+ provider.addAlgorithm("Signature.SHA384WITHDDSA", PREFIX + "DSASigner$detDSA384");
+ provider.addAlgorithm("Signature.SHA512WITHDDSA", PREFIX + "DSASigner$detDSA512");
+ provider.addAlgorithm("Signature.SHA3-224WITHDDSA", PREFIX + "DSASigner$detDSASha3_224");
+ provider.addAlgorithm("Signature.SHA3-256WITHDDSA", PREFIX + "DSASigner$detDSASha3_256");
+ provider.addAlgorithm("Signature.SHA3-384WITHDDSA", PREFIX + "DSASigner$detDSASha3_384");
+ provider.addAlgorithm("Signature.SHA3-512WITHDDSA", PREFIX + "DSASigner$detDSASha3_512");
+
addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
+ addSignatureAlgorithm(provider, "SHA3-224", "DSA", PREFIX + "DSASigner$dsaSha3_224", NISTObjectIdentifiers.id_dsa_with_sha3_224);
+ addSignatureAlgorithm(provider, "SHA3-256", "DSA", PREFIX + "DSASigner$dsaSha3_256", NISTObjectIdentifiers.id_dsa_with_sha3_256);
+ addSignatureAlgorithm(provider, "SHA3-384", "DSA", PREFIX + "DSASigner$dsaSha3_384", NISTObjectIdentifiers.id_dsa_with_sha3_384);
+ addSignatureAlgorithm(provider, "SHA3-512", "DSA", PREFIX + "DSASigner$dsaSha3_512", NISTObjectIdentifiers.id_dsa_with_sha3_512);
+
provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "DSA");
provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "DSA");
provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
index ebdb044b..05bf010b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -2,6 +2,7 @@ package org.bouncycastle.jcajce.provider.asymmetric;
import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
@@ -133,25 +134,12 @@ public class EC
provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
provider.addAlgorithm("Cipher.ECIES", PREFIX + "IESCipher$ECIES");
- provider.addAlgorithm("Cipher.ECIESwithAES", PREFIX + "IESCipher$ECIESwithAES");
- provider.addAlgorithm("Cipher.ECIESWITHAES", PREFIX + "IESCipher$ECIESwithAES");
- provider.addAlgorithm("Cipher.ECIESwithDESEDE", PREFIX + "IESCipher$ECIESwithDESede");
- provider.addAlgorithm("Cipher.ECIESWITHDESEDE", PREFIX + "IESCipher$ECIESwithDESede");
+
provider.addAlgorithm("Cipher.ECIESwithAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC");
provider.addAlgorithm("Cipher.ECIESWITHAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC");
provider.addAlgorithm("Cipher.ECIESwithDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC");
provider.addAlgorithm("Cipher.ECIESWITHDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC");
- provider.addAlgorithm("Cipher.OldECIES", PREFIX + "IESCipher$OldECIES");
- provider.addAlgorithm("Cipher.OldECIESwithAES", PREFIX + "IESCipher$OldECIESwithAES");
- provider.addAlgorithm("Cipher.OldECIESWITHAES", PREFIX + "IESCipher$OldECIESwithAES");
- provider.addAlgorithm("Cipher.OldECIESwithDESEDE", PREFIX + "IESCipher$OldECIESwithDESede");
- provider.addAlgorithm("Cipher.OldECIESWITHDESEDE", PREFIX + "IESCipher$OldECIESwithDESede");
- provider.addAlgorithm("Cipher.OldECIESwithAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC");
- provider.addAlgorithm("Cipher.OldECIESWITHAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC");
- provider.addAlgorithm("Cipher.OldECIESwithDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC");
- provider.addAlgorithm("Cipher.OldECIESWITHDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC");
-
provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
@@ -170,6 +158,10 @@ public class EC
provider.addAlgorithm("Signature.SHA256WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA256");
provider.addAlgorithm("Signature.SHA384WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA384");
provider.addAlgorithm("Signature.SHA512WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA512");
+ provider.addAlgorithm("Signature.SHA3-224WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_224");
+ provider.addAlgorithm("Signature.SHA3-256WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_256");
+ provider.addAlgorithm("Signature.SHA3-384WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_384");
+ provider.addAlgorithm("Signature.SHA3-512WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_512");
provider.addAlgorithm("Alg.Alias.Signature.DETECDSA", "ECDDSA");
provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDETECDSA", "SHA1WITHECDDSA");
@@ -182,6 +174,11 @@ public class EC
addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ addSignatureAlgorithm(provider, "SHA3-224", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_224", NISTObjectIdentifiers.id_ecdsa_with_sha3_224);
+ addSignatureAlgorithm(provider, "SHA3-256", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_256", NISTObjectIdentifiers.id_ecdsa_with_sha3_256);
+ addSignatureAlgorithm(provider, "SHA3-384", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_384", NISTObjectIdentifiers.id_ecdsa_with_sha3_384);
+ addSignatureAlgorithm(provider, "SHA3-512", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_512", NISTObjectIdentifiers.id_ecdsa_with_sha3_512);
+
addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
index 25957eaa..ebb483e3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -1,6 +1,7 @@
package org.bouncycastle.jcajce.provider.asymmetric;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
@@ -38,6 +39,11 @@ public class RSA
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-224WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-256WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-384WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-512WITHRSAANDMGF1", "PSS");
+
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
@@ -97,6 +103,11 @@ public class RSA
addPSSSignature(provider, "SHA512(224)", PREFIX + "PSSSignatureSpi$SHA512_224withRSA");
addPSSSignature(provider, "SHA512(256)", PREFIX + "PSSSignatureSpi$SHA512_256withRSA");
+ addPSSSignature(provider, "SHA3-224", PREFIX + "PSSSignatureSpi$SHA3_224withRSA");
+ addPSSSignature(provider, "SHA3-256", PREFIX + "PSSSignatureSpi$SHA3_256withRSA");
+ addPSSSignature(provider, "SHA3-384", PREFIX + "PSSSignatureSpi$SHA3_384withRSA");
+ addPSSSignature(provider, "SHA3-512", PREFIX + "PSSSignatureSpi$SHA3_512withRSA");
+
if (provider.hasAlgorithm("MessageDigest", "MD2"))
{
addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
@@ -132,8 +143,13 @@ public class RSA
addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
- addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", null);
- addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", null);
+ addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", PKCSObjectIdentifiers.sha512_224WithRSAEncryption);
+ addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", PKCSObjectIdentifiers.sha512_256WithRSAEncryption);
+
+ addDigestSignature(provider, "SHA3-224", PREFIX + "DigestSignatureSpi$SHA3_224", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224);
+ addDigestSignature(provider, "SHA3-256", PREFIX + "DigestSignatureSpi$SHA3_256", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256);
+ addDigestSignature(provider, "SHA3-384", PREFIX + "DigestSignatureSpi$SHA3_384", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384);
+ addDigestSignature(provider, "SHA3-512", PREFIX + "DigestSignatureSpi$SHA3_512", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512);
addISO9796Signature(provider, "SHA224", PREFIX + "ISOSignatureSpi$SHA224WithRSAEncryption");
addISO9796Signature(provider, "SHA256", PREFIX + "ISOSignatureSpi$SHA256WithRSAEncryption");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
index ef743095..1462a38b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
@@ -16,10 +16,12 @@ import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x9.DHDomainParameters;
import org.bouncycastle.asn1.x9.DomainParameters;
+import org.bouncycastle.asn1.x9.ValidationParams;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DHValidationParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
public class BCDHPublicKey
@@ -29,6 +31,7 @@ public class BCDHPublicKey
private BigInteger y;
+ private transient DHPublicKeyParameters dhPublicKey;
private transient DHParameterSpec dhSpec;
private transient SubjectPublicKeyInfo info;
@@ -37,6 +40,7 @@ public class BCDHPublicKey
{
this.y = spec.getY();
this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(spec.getP(), spec.getG()));
}
BCDHPublicKey(
@@ -44,6 +48,7 @@ public class BCDHPublicKey
{
this.y = key.getY();
this.dhSpec = key.getParams();
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
}
BCDHPublicKey(
@@ -51,6 +56,7 @@ public class BCDHPublicKey
{
this.y = params.getY();
this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ this.dhPublicKey = params;
}
BCDHPublicKey(
@@ -59,6 +65,7 @@ public class BCDHPublicKey
{
this.y = y;
this.dhSpec = dhSpec;
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
}
public BCDHPublicKey(
@@ -94,12 +101,23 @@ public class BCDHPublicKey
{
this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
}
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
}
else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
{
DomainParameters params = DomainParameters.getInstance(seq);
this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ ValidationParams validationParams = params.getValidationParams();
+ if (validationParams != null)
+ {
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(),
+ new DHValidationParameters(validationParams.getSeed(), validationParams.getPgenCounter().intValue())));
+ }
+ else
+ {
+ this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null));
+ }
}
else
{
@@ -137,6 +155,11 @@ public class BCDHPublicKey
return y;
}
+ public DHPublicKeyParameters engineGetKeyParameters()
+ {
+ return dhPublicKey;
+ }
+
private boolean isPKCSParam(ASN1Sequence seq)
{
if (seq.size() == 2)
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java
index 7983217c..6af56f53 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java
@@ -21,7 +21,7 @@ import javax.crypto.interfaces.DHKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
-import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.KeyEncoder;
import org.bouncycastle.crypto.agreement.DHBasicAgreement;
@@ -29,22 +29,24 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.IESEngine;
-import org.bouncycastle.crypto.engines.OldIESEngine;
import org.bouncycastle.crypto.generators.DHKeyPairGenerator;
import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
import org.bouncycastle.crypto.params.DHKeyParameters;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
-import org.bouncycastle.crypto.params.IESParameters;
import org.bouncycastle.crypto.params.IESWithCipherParameters;
+import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.parsers.DHIESPublicKeyParser;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.DHUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.IESUtil;
+import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.interfaces.IESKey;
@@ -57,6 +59,7 @@ public class IESCipher
extends CipherSpi
{
private final JcaJceHelper helper = new BCJcaJceHelper();
+ private final int ivLength;
private IESEngine engine;
private int state = -1;
@@ -71,11 +74,13 @@ public class IESCipher
public IESCipher(IESEngine engine)
{
this.engine = engine;
+ this.ivLength = 0;
}
- public IESCipher(OldIESEngine engine)
+ public IESCipher(IESEngine engine, int ivLength)
{
this.engine = engine;
+ this.ivLength = ivLength;
}
public int engineGetBlockSize()
@@ -106,6 +111,10 @@ public class IESCipher
public byte[] engineGetIV()
{
+ if (engineSpec != null)
+ {
+ return engineSpec.getNonce();
+ }
return null;
}
@@ -257,7 +266,13 @@ public class IESCipher
// Use default parameters (including cipher key size) if none are specified
if (engineSpec == null)
{
- this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher());
+ byte[] nonce = null;
+ if (ivLength != 0 && opmode == Cipher.ENCRYPT_MODE)
+ {
+ nonce = new byte[ivLength];
+ random.nextBytes(nonce);
+ }
+ this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher(), nonce);
}
else if (engineSpec instanceof IESParameterSpec)
{
@@ -268,6 +283,13 @@ public class IESCipher
throw new InvalidAlgorithmParameterException("must be passed IES parameters");
}
+ byte[] nonce = this.engineSpec.getNonce();
+
+ if (ivLength != 0 && (nonce == null || nonce.length != ivLength))
+ {
+ throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long");
+ }
+
// Parse the recipient's key
if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
{
@@ -329,7 +351,7 @@ public class IESCipher
}
catch (InvalidAlgorithmParameterException e)
{
- throw new IllegalArgumentException("can't handle supplied parameter spec");
+ throw new IllegalArgumentException("cannot handle supplied parameter spec: " + e.getMessage());
}
}
@@ -376,11 +398,16 @@ public class IESCipher
buffer.reset();
// Convert parameters for use in IESEngine
- IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
+ CipherParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
engineSpec.getEncodingV(),
engineSpec.getMacKeySize(),
engineSpec.getCipherKeySize());
+ if (engineSpec.getNonce() != null)
+ {
+ params = new ParametersWithIV(params, engineSpec.getNonce());
+ }
+
DHParameters dhParams = ((DHKeyParameters)key).getParameters();
byte[] V;
@@ -400,7 +427,7 @@ public class IESCipher
}
catch (Exception e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
}
@@ -439,7 +466,7 @@ public class IESCipher
}
catch (Exception e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
}
else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
@@ -453,7 +480,7 @@ public class IESCipher
}
catch (InvalidCipherTextException e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
}
else
@@ -489,76 +516,32 @@ public class IESCipher
public IES()
{
super(new IESEngine(new DHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest())));
+ new KDF2BytesGenerator(DigestFactory.createSHA1()),
+ new HMac(DigestFactory.createSHA1())));
}
}
- static public class IESwithDESede
+ static public class IESwithDESedeCBC
extends IESCipher
{
- public IESwithDESede()
+ public IESwithDESedeCBC()
{
super(new IESEngine(new DHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(new DESedeEngine())));
+ new KDF2BytesGenerator(DigestFactory.createSHA1()),
+ new HMac(DigestFactory.createSHA1()),
+ new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()))), 8);
}
}
- static public class IESwithAES
+ static public class IESwithAESCBC
extends IESCipher
{
- public IESwithAES()
+ public IESwithAESCBC()
{
super(new IESEngine(new DHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(new AESEngine())));
- }
- }
-
- /**
- * Backwards compatibility.
- */
- static public class OldIESwithCipher
- extends IESCipher
- {
- public OldIESwithCipher(BlockCipher baseCipher)
- {
- super(new OldIESEngine(new DHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(baseCipher)));
- }
- }
-
- static public class OldIES
- extends IESCipher
- {
- public OldIES()
- {
- super(new OldIESEngine(new DHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest())));
- }
- }
-
- static public class OldIESwithDESede
- extends OldIESwithCipher
- {
- public OldIESwithDESede()
- {
- super(new DESedeEngine());
- }
- }
-
- static public class OldIESwithAES
- extends OldIESwithCipher
- {
- public OldIESwithAES()
- {
- super(new AESEngine());
+ new KDF2BytesGenerator(DigestFactory.createSHA1()),
+ new HMac(DigestFactory.createSHA1()),
+ new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()))), 16);
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
index 08ad51ad..b75b5e1a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -18,6 +18,7 @@ import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
@@ -29,10 +30,15 @@ import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
public class KeyAgreementSpi
extends BaseAgreementSpi
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
private BigInteger x;
private BigInteger p;
private BigInteger g;
+ private BigInteger result;
+
public KeyAgreementSpi()
{
super("Diffie-Hellman", null);
@@ -99,14 +105,22 @@ public class KeyAgreementSpi
throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
}
- if (lastPhase)
+ BigInteger peerY = ((DHPublicKey)key).getY();
+ if (peerY == null || peerY.compareTo(TWO) < 0
+ || peerY.compareTo(p.subtract(ONE)) >= 0)
{
- result = ((DHPublicKey)key).getY().modPow(x, p);
- return null;
+ throw new InvalidKeyException("Invalid DH PublicKey");
}
- else
+
+ result = peerY.modPow(x, p);
+ if (result.compareTo(ONE) == 0)
+ {
+ throw new InvalidKeyException("Shared key can't be 1");
+ }
+
+ if (lastPhase)
{
- result = ((DHPublicKey)key).getY().modPow(x, p);
+ return null;
}
return new BCDHPublicKey(result, pubKey.getParams());
@@ -214,12 +228,17 @@ public class KeyAgreementSpi
this.x = this.result = privKey.getX();
}
+ protected byte[] calcSecret()
+ {
+ return bigIntToBytes(result);
+ }
+
public static class DHwithRFC2631KDF
extends KeyAgreementSpi
{
public DHwithRFC2631KDF()
{
- super("DHwithRFC2631KDF", new DHKEKGenerator(new SHA1Digest()));
+ super("DHwithRFC2631KDF", new DHKEKGenerator(DigestFactory.createSHA1()));
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
index 9565bd2d..32e9b496 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
@@ -19,6 +19,7 @@ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
public class KeyFactorySpi
extends BaseKeyFactorySpi
@@ -82,7 +83,14 @@ public class KeyFactorySpi
{
if (keySpec instanceof DHPublicKeySpec)
{
- return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+ try
+ {
+ return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtendedInvalidKeySpecException(e.getMessage(), e);
+ }
}
return super.engineGeneratePublic(keySpec);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
index 48da0203..793f7299 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
@@ -42,6 +42,7 @@ public class KeyPairGeneratorSpi
{
this.strength = strength;
this.random = random;
+ this.initialised = false;
}
public void initialize(
@@ -113,7 +114,6 @@ public class KeyPairGeneratorSpi
DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic();
DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
- return new KeyPair(new BCDHPublicKey(pub),
- new BCDHPrivateKey(priv));
+ return new KeyPair(new BCDHPublicKey(pub), new BCDHPrivateKey(priv));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
index 3a7b3121..13223cb6 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
@@ -24,15 +24,19 @@ public class BCDSAPublicKey
implements DSAPublicKey
{
private static final long serialVersionUID = 1752452449903495175L;
+ private static BigInteger ZERO = BigInteger.valueOf(0);
private BigInteger y;
- private transient DSAParams dsaSpec;
+
+ private transient DSAPublicKeyParameters lwKeyParams;
+ private transient DSAParams dsaSpec;
BCDSAPublicKey(
DSAPublicKeySpec spec)
{
this.y = spec.getY();
this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
}
BCDSAPublicKey(
@@ -40,27 +44,27 @@ public class BCDSAPublicKey
{
this.y = key.getY();
this.dsaSpec = key.getParams();
+ this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
}
BCDSAPublicKey(
DSAPublicKeyParameters params)
{
this.y = params.getY();
- this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
- }
-
- BCDSAPublicKey(
- BigInteger y,
- DSAParameterSpec dsaSpec)
- {
- this.y = y;
- this.dsaSpec = dsaSpec;
+ if (params != null)
+ {
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+ else
+ {
+ this.dsaSpec = null;
+ }
+ this.lwKeyParams = params;
}
public BCDSAPublicKey(
SubjectPublicKeyInfo info)
{
-
ASN1Integer derY;
try
@@ -80,6 +84,12 @@ public class BCDSAPublicKey
this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
}
+ else
+ {
+ this.dsaSpec = null;
+ }
+
+ this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
}
private boolean isNotNull(ASN1Encodable parameters)
@@ -97,6 +107,11 @@ public class BCDSAPublicKey
return "X.509";
}
+ DSAPublicKeyParameters engineGetKeyParameters()
+ {
+ return lwKeyParams;
+ }
+
public byte[] getEncoded()
{
if (dsaSpec == null)
@@ -130,8 +145,15 @@ public class BCDSAPublicKey
public int hashCode()
{
- return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ if (dsaSpec != null)
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+ else
+ {
+ return this.getY().hashCode();
+ }
}
public boolean equals(
@@ -143,11 +165,19 @@ public class BCDSAPublicKey
}
DSAPublicKey other = (DSAPublicKey)o;
-
- return this.getY().equals(other.getY())
- && this.getParams().getG().equals(other.getParams().getG())
- && this.getParams().getP().equals(other.getParams().getP())
- && this.getParams().getQ().equals(other.getParams().getQ());
+
+ if (this.dsaSpec != null)
+ {
+ return this.getY().equals(other.getY())
+ && other.getParams() != null
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+ else
+ {
+ return this.getY().equals(other.getY()) && other.getParams() == null;
+ }
}
private void readObject(
@@ -156,7 +186,16 @@ public class BCDSAPublicKey
{
in.defaultReadObject();
- this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ BigInteger p = (BigInteger)in.readObject();
+ if (p.equals(ZERO))
+ {
+ this.dsaSpec = null;
+ }
+ else
+ {
+ this.dsaSpec = new DSAParameterSpec(p, (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+ this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
}
private void writeObject(
@@ -165,8 +204,15 @@ public class BCDSAPublicKey
{
out.defaultWriteObject();
- out.writeObject(dsaSpec.getP());
- out.writeObject(dsaSpec.getQ());
- out.writeObject(dsaSpec.getG());
+ if (dsaSpec == null)
+ {
+ out.writeObject(ZERO);
+ }
+ else
+ {
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
index ade49b3d..a9aeff59 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -8,7 +8,6 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.SignatureSpi;
-import java.security.interfaces.DSAKey;
import java.security.spec.AlgorithmParameterSpec;
import org.bouncycastle.asn1.ASN1Encoding;
@@ -17,19 +16,16 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DSA;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.NullDigest;
import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
+import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.util.Arrays;
public class DSASigner
extends SignatureSpi
@@ -51,34 +47,7 @@ public class DSASigner
PublicKey publicKey)
throws InvalidKeyException
{
- CipherParameters param;
-
- if (publicKey instanceof DSAKey)
- {
- param = DSAUtil.generatePublicKeyParameter(publicKey);
- }
- else
- {
- try
- {
- byte[] bytes = publicKey.getEncoded();
-
- publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
-
- if (publicKey instanceof DSAKey)
- {
- param = DSAUtil.generatePublicKeyParameter(publicKey);
- }
- else
- {
- throw new InvalidKeyException("can't recognise key type in DSA based signer");
- }
- }
- catch (Exception e)
- {
- throw new InvalidKeyException("can't recognise key type in DSA based signer");
- }
- }
+ CipherParameters param = DSAUtil.generatePublicKeyParameter(publicKey);
digest.reset();
signer.init(false, param);
@@ -97,9 +66,7 @@ public class DSASigner
PrivateKey privateKey)
throws InvalidKeyException
{
- CipherParameters param;
-
- param = DSAUtil.generatePrivateKeyParameter(privateKey);
+ CipherParameters param = DSAUtil.generatePrivateKeyParameter(privateKey);
if (random != null)
{
@@ -206,6 +173,15 @@ public class DSASigner
throws IOException
{
ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ if (s.size() != 2)
+ {
+ throw new IOException("malformed signature");
+ }
+ if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER)))
+ {
+ throw new IOException("malformed signature");
+ }
+
return new BigInteger[]{
((ASN1Integer)s.getObjectAt(0)).getValue(),
((ASN1Integer)s.getObjectAt(1)).getValue()
@@ -217,7 +193,7 @@ public class DSASigner
{
public stdDSA()
{
- super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner());
}
}
@@ -226,7 +202,7 @@ public class DSASigner
{
public detDSA()
{
- super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest())));
+ super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())));
}
}
@@ -235,7 +211,7 @@ public class DSASigner
{
public dsa224()
{
- super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
}
}
@@ -244,7 +220,7 @@ public class DSASigner
{
public detDSA224()
{
- super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest())));
+ super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())));
}
}
@@ -253,7 +229,7 @@ public class DSASigner
{
public dsa256()
{
- super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
}
}
@@ -262,7 +238,7 @@ public class DSASigner
{
public detDSA256()
{
- super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest())));
+ super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())));
}
}
@@ -271,7 +247,7 @@ public class DSASigner
{
public dsa384()
{
- super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner());
}
}
@@ -280,7 +256,7 @@ public class DSASigner
{
public detDSA384()
{
- super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest())));
+ super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())));
}
}
@@ -289,7 +265,7 @@ public class DSASigner
{
public dsa512()
{
- super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner());
}
}
@@ -298,7 +274,79 @@ public class DSASigner
{
public detDSA512()
{
- super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest())));
+ super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())));
+ }
+ }
+
+ static public class dsaSha3_224
+ extends DSASigner
+ {
+ public dsaSha3_224()
+ {
+ super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSASha3_224
+ extends DSASigner
+ {
+ public detDSASha3_224()
+ {
+ super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())));
+ }
+ }
+
+ static public class dsaSha3_256
+ extends DSASigner
+ {
+ public dsaSha3_256()
+ {
+ super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSASha3_256
+ extends DSASigner
+ {
+ public detDSASha3_256()
+ {
+ super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())));
+ }
+ }
+
+ static public class dsaSha3_384
+ extends DSASigner
+ {
+ public dsaSha3_384()
+ {
+ super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSASha3_384
+ extends DSASigner
+ {
+ public detDSASha3_384()
+ {
+ super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())));
+ }
+ }
+
+ static public class dsaSha3_512
+ extends DSASigner
+ {
+ public dsaSha3_512()
+ {
+ super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSASha3_512
+ extends DSASigner
+ {
+ public detDSASha3_512()
+ {
+ super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
index 5e940ec1..8f83bf89 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -3,11 +3,14 @@ package org.bouncycastle.jcajce.provider.asymmetric.dsa;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
@@ -40,19 +43,42 @@ public class DSAUtil
return false;
}
+ static DSAParameters toDSAParameters(DSAParams spec)
+ {
+ if (spec != null)
+ {
+ return new DSAParameters(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ return null;
+ }
+
static public AsymmetricKeyParameter generatePublicKeyParameter(
PublicKey key)
throws InvalidKeyException
{
- if (key instanceof DSAPublicKey)
+ if (key instanceof BCDSAPublicKey)
{
- DSAPublicKey k = (DSAPublicKey)key;
+ return ((BCDSAPublicKey)key).engineGetKeyParameters();
+ }
- return new DSAPublicKeyParameters(k.getY(),
- new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+ if (key instanceof DSAPublicKey)
+ {
+ return new BCDSAPublicKey((DSAPublicKey)key).engineGetKeyParameters();
}
- throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+ try
+ {
+ byte[] bytes = key.getEncoded();
+
+ BCDSAPublicKey bckey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ return bckey.engineGetKeyParameters();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+ }
}
static public AsymmetricKeyParameter generatePrivateKeyParameter(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
index a36f3dd7..7816320d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
@@ -109,7 +109,20 @@ public class KeyFactorySpi
{
if (keySpec instanceof DSAPublicKeySpec)
{
- return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+ try
+ {
+ return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+ }
+ catch (final Exception e)
+ {
+ throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage())
+ {
+ public Throwable getCause()
+ {
+ return e;
+ }
+ };
+ }
}
return super.engineGeneratePublic(keySpec);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
index d2c2c712..bacbb6c2 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
@@ -6,18 +6,26 @@ import java.security.KeyPair;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
+import java.util.Hashtable;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+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.util.Integers;
+import org.bouncycastle.util.Properties;
public class KeyPairGeneratorSpi
extends java.security.KeyPairGenerator
{
+ private static Hashtable params = new Hashtable();
+ private static Object lock = new Object();
+
DSAKeyGenerationParameters param;
DSAKeyPairGenerator engine = new DSAKeyPairGenerator();
int strength = 1024;
@@ -41,6 +49,7 @@ public class KeyPairGeneratorSpi
this.strength = strength;
this.random = random;
+ this.initialised = false;
}
public void initialize(
@@ -64,10 +73,65 @@ public class KeyPairGeneratorSpi
{
if (!initialised)
{
- DSAParametersGenerator pGen = new DSAParametersGenerator();
+ Integer paramStrength = Integers.valueOf(strength);
+
+ if (params.containsKey(paramStrength))
+ {
+ param = (DSAKeyGenerationParameters)params.get(paramStrength);
+ }
+ else
+ {
+ synchronized (lock)
+ {
+ // we do the check again in case we were blocked by a generator for
+ // our key size.
+ if (params.containsKey(paramStrength))
+ {
+ param = (DSAKeyGenerationParameters)params.get(paramStrength);
+ }
+ else
+ {
+ DSAParametersGenerator pGen;
+ DSAParameterGenerationParameters dsaParams;
+
+ // Typical combination of keysize and size of q.
+ // keysize = 1024, q's size = 160
+ // keysize = 2048, q's size = 224
+ // keysize = 2048, q's size = 256
+ // keysize = 3072, q's size = 256
+ // For simplicity if keysize is greater than 1024 then we choose q's size to be 256.
+ // For legacy keysize that is less than 1024-bit, we just use the 186-2 style parameters
+ if (strength == 1024)
+ {
+ pGen = new DSAParametersGenerator();
+ if (Properties.isOverrideSet("org.bouncycastle.dsa.FIPS186-2for1024bits"))
+ {
+ pGen.init(strength, certainty, random);
+ }
+ else
+ {
+ dsaParams = new DSAParameterGenerationParameters(1024, 160, certainty, random);
+ pGen.init(dsaParams);
+ }
+ }
+ else if (strength > 1024)
+ {
+ dsaParams = new DSAParameterGenerationParameters(strength, 256, certainty, random);
+ pGen = new DSAParametersGenerator(new SHA256Digest());
+ pGen.init(dsaParams);
+ }
+ else
+ {
+ pGen = new DSAParametersGenerator();
+ pGen.init(strength, certainty, random);
+ }
+ param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+
+ params.put(paramStrength, param);
+ }
+ }
+ }
- pGen.init(strength, certainty, random);
- param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
engine.init(param);
initialised = true;
}
@@ -76,7 +140,6 @@ public class KeyPairGeneratorSpi
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic();
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
- return new KeyPair(new BCDSAPublicKey(pub),
- new BCDSAPrivateKey(priv));
+ return new KeyPair(new BCDSAPublicKey(pub), new BCDSAPrivateKey(priv));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java
index b1aaf2d9..bdd9920d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java
@@ -293,12 +293,12 @@ public class BCDSTU4145PrivateKey
curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
}
params = new X962Parameters(curveOid);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS());
}
else if (ecSpec == null)
{
params = new X962Parameters(DERNull.INSTANCE);
- orderBitLength = ECUtil.getOrderBitLength(null, this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, null, this.getS());
}
else
{
@@ -312,7 +312,7 @@ public class BCDSTU4145PrivateKey
ecSpec.getCurve().getSeed());
params = new X962Parameters(ecP);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS());
}
PrivateKeyInfo info;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java
index 957732d3..2c9fdab3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java
@@ -30,7 +30,9 @@ import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.interfaces.ECPointEncoder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
@@ -48,14 +50,14 @@ public class BCDSTU4145PublicKey
private String algorithm = "DSTU4145";
private boolean withCompression;
- private transient org.bouncycastle.math.ec.ECPoint q;
+ private transient ECPublicKeyParameters ecPublicKey;
private transient ECParameterSpec ecSpec;
private transient DSTU4145Params dstuParams;
public BCDSTU4145PublicKey(
BCDSTU4145PublicKey key)
{
- this.q = key.q;
+ this.ecPublicKey = key.ecPublicKey;
this.ecSpec = key.ecSpec;
this.withCompression = key.withCompression;
this.dstuParams = key.dstuParams;
@@ -65,29 +67,28 @@ public class BCDSTU4145PublicKey
ECPublicKeySpec spec)
{
this.ecSpec = spec.getParams();
- this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, ecSpec));
}
public BCDSTU4145PublicKey(
- org.bouncycastle.jce.spec.ECPublicKeySpec spec)
+ org.bouncycastle.jce.spec.ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
{
- this.q = spec.getQ();
-
if (spec.getParams() != null) // can be null if implictlyCa
{
ECCurve curve = spec.getParams().getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+ // this may seem a little long-winded but it's how we pick up the custom curve.
+ this.ecPublicKey = new ECPublicKeyParameters(
+ spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams()));
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
}
else
{
- if (q.getCurve() == null)
- {
- org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
- q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
- }
+ this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null));
this.ecSpec = null;
}
}
@@ -100,7 +101,7 @@ public class BCDSTU4145PublicKey
ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
if (spec == null)
{
@@ -119,10 +120,9 @@ public class BCDSTU4145PublicKey
ECPublicKeyParameters params,
org.bouncycastle.jce.spec.ECParameterSpec spec)
{
- ECDomainParameters dp = params.getParameters();
+ ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
- this.q = params.getQ();
if (spec == null)
{
@@ -136,6 +136,8 @@ public class BCDSTU4145PublicKey
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
}
+
+ this.ecPublicKey = params;
}
/*
@@ -146,7 +148,7 @@ public class BCDSTU4145PublicKey
ECPublicKeyParameters params)
{
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
this.ecSpec = null;
}
@@ -161,14 +163,6 @@ public class BCDSTU4145PublicKey
dp.getH().intValue());
}
- public BCDSTU4145PublicKey(
- ECPublicKey key)
- {
- this.algorithm = key.getAlgorithm();
- this.ecSpec = key.getParams();
- this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
- }
-
BCDSTU4145PublicKey(
SubjectPublicKeyInfo info)
{
@@ -241,9 +235,6 @@ public class BCDSTU4145PublicKey
ECCurve curve = spec.getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
- //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
- this.q = DSTU4145PointEncoder.decodePoint(curve, keyEnc);
-
if (dstuParams.isNamedCurve())
{
ecSpec = new ECNamedCurveSpec(
@@ -263,6 +254,9 @@ public class BCDSTU4145PublicKey
spec.getG().getAffineYCoord().toBigInteger()),
spec.getN(), spec.getH().intValue());
}
+
+ //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+ this.ecPublicKey = new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(curve, keyEnc), EC5Util.getDomainParameters(null, ecSpec));
}
public byte[] getSbox()
@@ -317,7 +311,7 @@ public class BCDSTU4145PublicKey
}
}
- byte[] encKey = DSTU4145PointEncoder.encodePoint(this.q);
+ byte[] encKey = DSTU4145PointEncoder.encodePoint(ecPublicKey.getQ());
try
{
@@ -348,11 +342,15 @@ public class BCDSTU4145PublicKey
public ECPoint getW()
{
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
+
return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
}
public org.bouncycastle.math.ec.ECPoint getQ()
{
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
+
if (ecSpec == null)
{
return q.getDetachedPoint();
@@ -361,10 +359,10 @@ public class BCDSTU4145PublicKey
return q;
}
- public org.bouncycastle.math.ec.ECPoint engineGetQ()
- {
- return q;
- }
+ ECPublicKeyParameters engineGetKeyParameters()
+ {
+ return ecPublicKey;
+ }
org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
{
@@ -382,8 +380,8 @@ public class BCDSTU4145PublicKey
String nl = Strings.lineSeparator();
buf.append("EC Public Key").append(nl);
- buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
- buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" X: ").append(getQ().getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(getQ().getAffineYCoord().toBigInteger().toString(16)).append(nl);
return buf.toString();
}
@@ -402,12 +400,12 @@ public class BCDSTU4145PublicKey
BCDSTU4145PublicKey other = (BCDSTU4145PublicKey)o;
- return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
}
public int hashCode()
{
- return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode();
}
private void readObject(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java
index 95a91dea..f2ff8381 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java
@@ -124,7 +124,7 @@ public class KeyFactorySpi
{
if (keySpec instanceof ECPublicKeySpec)
{
- return new BCDSTU4145PublicKey((ECPublicKeySpec)keySpec);
+ return new BCDSTU4145PublicKey((ECPublicKeySpec)keySpec, BouncyCastleProvider.CONFIGURATION);
}
else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java
index f39eb7fa..2dfb20f9 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java
@@ -75,7 +75,7 @@ public class KeyPairGeneratorSpi
ECParameterSpec p = (ECParameterSpec)params;
this.ecParams = params;
- param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random);
engine.init(param);
initialised = true;
@@ -136,7 +136,7 @@ public class KeyPairGeneratorSpi
ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
this.ecParams = params;
- param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random);
engine.init(param);
initialised = true;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java
index 1b9ce706..7a5f0091 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java
@@ -54,31 +54,13 @@ public class SignatureSpi
{
CipherParameters param;
- if (publicKey instanceof ECPublicKey)
+ if (publicKey instanceof BCDSTU4145PublicKey)
{
- param = ECUtil.generatePublicKeyParameter(publicKey);
+ param = ((BCDSTU4145PublicKey)publicKey).engineGetKeyParameters();
}
else
{
- try
- {
- byte[] bytes = publicKey.getEncoded();
-
- publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
-
- if (publicKey instanceof ECPublicKey)
- {
- param = ECUtil.generatePublicKeyParameter(publicKey);
- }
- else
- {
- throw new InvalidKeyException("can't recognise key type in DSA based signer");
- }
- }
- catch (Exception e)
- {
- throw new InvalidKeyException("can't recognise key type in DSA based signer");
- }
+ param = ECUtil.generatePublicKeyParameter(publicKey);
}
digest = new GOST3411Digest(expandSbox(((BCDSTU4145PublicKey)publicKey).getSbox()));
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
index 6af71e80..9f56a55a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
@@ -14,6 +14,7 @@ import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECCurve;
public class AlgorithmParametersSpi
@@ -45,7 +46,14 @@ public class AlgorithmParametersSpi
}
else if (algorithmParameterSpec instanceof ECParameterSpec)
{
- curveName = null;
+ if (algorithmParameterSpec instanceof ECNamedCurveSpec)
+ {
+ curveName = ((ECNamedCurveSpec)algorithmParameterSpec).getName();
+ }
+ else
+ {
+ curveName = null;
+ }
ecParameterSpec = (ECParameterSpec)algorithmParameterSpec;
}
else
@@ -73,7 +81,13 @@ public class AlgorithmParametersSpi
if (params.isNamedCurve())
{
- curveName = ECNamedCurveTable.getName(ASN1ObjectIdentifier.getInstance(params.getParameters()));
+ ASN1ObjectIdentifier curveId = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveName = ECNamedCurveTable.getName(curveId);
+ if (curveName == null)
+ {
+ curveName = curveId.getId();
+ }
}
ecParameterSpec = EC5Util.convertToSpec(params, curve);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
index e69942a2..815bcac0 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -17,12 +17,10 @@ import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
-import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
@@ -33,7 +31,6 @@ import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.interfaces.ECPointEncoder;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.Strings;
@@ -181,7 +178,14 @@ public class BCECPrivateKey
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
}
- publicKey = getPublicKeyDetails(pubKey);
+ try
+ {
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+ catch (Exception e)
+ {
+ publicKey = null; // not all curves are encodable
+ }
}
public BCECPrivateKey(
@@ -253,38 +257,16 @@ public class BCECPrivateKey
*/
public byte[] getEncoded()
{
- X962Parameters params;
- int orderBitLength;
+ X962Parameters params = ECUtils.getDomainParametersFromName(ecSpec, withCompression);
- if (ecSpec instanceof ECNamedCurveSpec)
- {
- ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
- if (curveOid == null) // guess it's the OID
- {
- curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
- }
-
- params = new X962Parameters(curveOid);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
- }
- else if (ecSpec == null)
+ int orderBitLength;
+ if (ecSpec == null)
{
- params = new X962Parameters(DERNull.INSTANCE);
- orderBitLength = ECUtil.getOrderBitLength(null, this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS());
}
else
{
- ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
-
- X9ECParameters ecP = new X9ECParameters(
- curve,
- EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
- ecSpec.getOrder(),
- BigInteger.valueOf(ecSpec.getCofactor()),
- ecSpec.getCurve().getSeed());
-
- params = new X962Parameters(ecP);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS());
}
PrivateKeyInfo info;
@@ -420,9 +402,10 @@ public class BCECPrivateKey
byte[] enc = (byte[])in.readObject();
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+
populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
- this.configuration = BouncyCastleProvider.CONFIGURATION;
this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
index c3f0dd02..443c5f63 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -3,7 +3,6 @@ package org.bouncycastle.jcajce.provider.asymmetric.ec;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.math.BigInteger;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
@@ -11,16 +10,13 @@ import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
-import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9IntegerConverter;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
@@ -32,7 +28,6 @@ import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.interfaces.ECPointEncoder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.Strings;
@@ -44,7 +39,7 @@ public class BCECPublicKey
private String algorithm = "EC";
private boolean withCompression;
- private transient org.bouncycastle.math.ec.ECPoint q;
+ private transient ECPublicKeyParameters ecPublicKey;
private transient ECParameterSpec ecSpec;
private transient ProviderConfiguration configuration;
@@ -53,7 +48,7 @@ public class BCECPublicKey
BCECPublicKey key)
{
this.algorithm = algorithm;
- this.q = key.q;
+ this.ecPublicKey = key.ecPublicKey;
this.ecSpec = key.ecSpec;
this.withCompression = key.withCompression;
this.configuration = key.configuration;
@@ -66,7 +61,7 @@ public class BCECPublicKey
{
this.algorithm = algorithm;
this.ecSpec = spec.getParams();
- this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(configuration, spec.getParams()));
this.configuration = configuration;
}
@@ -76,7 +71,6 @@ public class BCECPublicKey
ProviderConfiguration configuration)
{
this.algorithm = algorithm;
- this.q = spec.getQ();
if (spec.getParams() != null) // can be null if implictlyCa
{
@@ -84,17 +78,15 @@ public class BCECPublicKey
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
// this may seem a little long-winded but it's how we pick up the custom curve.
- this.q = EC5Util.convertCurve(ellipticCurve).createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger());
+ this.ecPublicKey = new ECPublicKeyParameters(
+ spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams()));
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
}
else
{
- if (q.getCurve() == null)
- {
- org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
+ org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
- q = s.getCurve().createPoint(q.getXCoord().toBigInteger(), q.getYCoord().toBigInteger(), false);
- }
+ this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null));
this.ecSpec = null;
}
@@ -110,7 +102,7 @@ public class BCECPublicKey
ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
if (spec == null)
{
@@ -149,8 +141,7 @@ public class BCECPublicKey
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
}
- this.q = EC5Util.convertCurve(ecSpec.getCurve()).createPoint(params.getQ().getAffineXCoord().toBigInteger(), params.getQ().getAffineYCoord().toBigInteger());
-
+ this.ecPublicKey = params;
this.configuration = configuration;
}
@@ -163,7 +154,7 @@ public class BCECPublicKey
ProviderConfiguration configuration)
{
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
this.ecSpec = null;
this.configuration = configuration;
}
@@ -174,7 +165,7 @@ public class BCECPublicKey
{
this.algorithm = key.getAlgorithm();
this.ecSpec = key.getParams();
- this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(configuration, key.getParams()));
}
BCECPublicKey(
@@ -200,7 +191,7 @@ public class BCECPublicKey
private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
{
- X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters());
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters());
ECCurve curve = EC5Util.getCurve(configuration, params);
ecSpec = EC5Util.convertToSpec(params, curve);
@@ -231,7 +222,7 @@ public class BCECPublicKey
X9ECPoint derQ = new X9ECPoint(curve, key);
- this.q = derQ.getPoint();
+ this.ecPublicKey = new ECPublicKeyParameters(derQ.getPoint(), ECUtil.getDomainParameters(configuration, params));
}
public String getAlgorithm()
@@ -246,72 +237,15 @@ public class BCECPublicKey
public byte[] getEncoded()
{
- ASN1Encodable params;
- SubjectPublicKeyInfo info;
-
- if (ecSpec instanceof ECNamedCurveSpec)
- {
- ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
- if (curveOid == null)
- {
- curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
- }
- params = new X962Parameters(curveOid);
- }
- else if (ecSpec == null)
- {
- params = new X962Parameters(DERNull.INSTANCE);
- }
- else
- {
- ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
-
- X9ECParameters ecP = new X9ECParameters(
- curve,
- EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
- ecSpec.getOrder(),
- BigInteger.valueOf(ecSpec.getCofactor()),
- ecSpec.getCurve().getSeed());
-
- params = new X962Parameters(ecP);
- }
-
- ECCurve curve = this.engineGetQ().getCurve();
- ASN1OctetString p;
+ ASN1Encodable params = ECUtils.getDomainParametersFromName(ecSpec, withCompression);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(ecPublicKey.getQ(), withCompression).toASN1Primitive());
// stored curve is null if ImplicitlyCa
- if (ecSpec == null)
- {
- p = (ASN1OctetString)
- new X9ECPoint(curve.createPoint(this.getQ().getXCoord().toBigInteger(), this.getQ().getYCoord().toBigInteger(), withCompression)).toASN1Primitive();
- }
- else
- {
- p = (ASN1OctetString)
- new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
- }
-
- info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
}
- private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
- {
- byte[] val = bI.toByteArray();
- if (val.length < 32)
- {
- byte[] tmp = new byte[32];
- System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
- val = tmp;
- }
-
- for (int i = 0; i != 32; i++)
- {
- encKey[offSet + i] = val[val.length - 1 - i];
- }
- }
-
public ECParameterSpec getParams()
{
return ecSpec;
@@ -329,11 +263,15 @@ public class BCECPublicKey
public ECPoint getW()
{
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
+
return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
}
public org.bouncycastle.math.ec.ECPoint getQ()
{
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
+
if (ecSpec == null)
{
return q.getDetachedPoint();
@@ -342,9 +280,9 @@ public class BCECPublicKey
return q;
}
- public org.bouncycastle.math.ec.ECPoint engineGetQ()
+ ECPublicKeyParameters engineGetKeyParameters()
{
- return q;
+ return ecPublicKey;
}
org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
@@ -361,10 +299,11 @@ public class BCECPublicKey
{
StringBuffer buf = new StringBuffer();
String nl = Strings.lineSeparator();
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
buf.append("EC Public Key").append(nl);
- buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
- buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
return buf.toString();
@@ -384,12 +323,12 @@ public class BCECPublicKey
BCECPublicKey other = (BCECPublicKey)o;
- return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
}
public int hashCode()
{
- return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode();
}
private void readObject(
@@ -400,9 +339,9 @@ public class BCECPublicKey
byte[] enc = (byte[])in.readObject();
- populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
-
this.configuration = BouncyCastleProvider.CONFIGURATION;
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
}
private void writeObject(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
index dc92e0e4..8a5c834c 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
@@ -1,13 +1,30 @@
package org.bouncycastle.jcajce.provider.asymmetric.ec;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
class ECUtils
{
+ static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ return (key instanceof BCECPublicKey) ? ((BCECPublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key);
+ }
+
static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec)
{
return getDomainParametersFromName(genSpec.getName());
@@ -42,4 +59,38 @@ class ECUtils
}
return domainParameters;
}
+
+ static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean withCompression)
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ return params;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java
index 0cc0c2f3..f500350e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java
@@ -27,7 +27,6 @@ import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.IESEngine;
-import org.bouncycastle.crypto.engines.OldIESEngine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
@@ -42,8 +41,10 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.IESWithCipherParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.parsers.ECIESPublicKeyParser;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.IESUtil;
+import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.interfaces.ECKey;
@@ -108,6 +109,10 @@ public class IESCipher
public byte[] engineGetIV()
{
+ if (engineSpec != null)
+ {
+ return engineSpec.getNonce();
+ }
return null;
}
@@ -163,7 +168,7 @@ public class IESCipher
if (otherKeyParameter == null)
{
- len2 = 1 + 2 * (((ECKeyParameters)key).getParameters().getCurve().getFieldSize() + 7) / 8;
+ len2 = 2 * (((ECKeyParameters)key).getParameters().getCurve().getFieldSize() + 7) / 8;
}
else
{
@@ -189,7 +194,7 @@ public class IESCipher
if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
{
- return buffer.size() + len1 + len2 + len3;
+ return buffer.size() + len1 + 1 + len2 + len3;
}
else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
{
@@ -264,7 +269,13 @@ public class IESCipher
// Use default parameters (including cipher key size) if none are specified
if (engineSpec == null)
{
- this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher());
+ byte[] nonce = null;
+ if (ivLength != 0 && opmode == Cipher.ENCRYPT_MODE)
+ {
+ nonce = new byte[ivLength];
+ random.nextBytes(nonce);
+ }
+ this.engineSpec = IESUtil.guessParameterSpec(engine.getCipher(), nonce);
}
else if (engineSpec instanceof IESParameterSpec)
{
@@ -277,16 +288,9 @@ public class IESCipher
byte[] nonce = this.engineSpec.getNonce();
- if (nonce != null)
+ if (ivLength != 0 && (nonce == null || nonce.length != ivLength))
{
- if (ivLength == 0)
- {
- throw new InvalidAlgorithmParameterException("NONCE present in IES Parameters when none required");
- }
- else if (nonce.length != ivLength)
- {
- throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long");
- }
+ throw new InvalidAlgorithmParameterException("NONCE in IES Parameters needs to be " + ivLength + " bytes long");
}
// Parse the recipient's key
@@ -294,13 +298,13 @@ public class IESCipher
{
if (key instanceof PublicKey)
{
- this.key = ECUtil.generatePublicKeyParameter((PublicKey)key);
+ this.key = ECUtils.generatePublicKeyParameter((PublicKey)key);
}
else if (key instanceof IESKey)
{
IESKey ieKey = (IESKey)key;
- this.key = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.key = ECUtils.generatePublicKeyParameter(ieKey.getPublic());
this.otherKeyParameter = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
}
else
@@ -318,7 +322,7 @@ public class IESCipher
{
IESKey ieKey = (IESKey)key;
- this.otherKeyParameter = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.otherKeyParameter = ECUtils.generatePublicKeyParameter(ieKey.getPublic());
this.key = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
}
else
@@ -351,7 +355,7 @@ public class IESCipher
}
catch (InvalidAlgorithmParameterException e)
{
- throw new IllegalArgumentException("can't handle supplied parameter spec");
+ throw new IllegalArgumentException("cannot handle supplied parameter spec: " + e.getMessage());
}
}
@@ -428,7 +432,7 @@ public class IESCipher
}
catch (Exception e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
}
@@ -454,11 +458,10 @@ public class IESCipher
return engine.processBlock(in, 0, in.length);
}
- catch (Exception e)
+ catch (final Exception e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
-
}
else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
{
@@ -471,7 +474,7 @@ public class IESCipher
}
catch (InvalidCipherTextException e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to process block", e);
}
}
else
@@ -505,49 +508,23 @@ public class IESCipher
public ECIES()
{
super(new IESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest())));
+ new KDF2BytesGenerator(DigestFactory.createSHA1()),
+ new HMac(DigestFactory.createSHA1())));
}
}
static public class ECIESwithCipher
extends IESCipher
{
- public ECIESwithCipher(BlockCipher cipher)
- {
- super(new IESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(cipher)));
- }
-
public ECIESwithCipher(BlockCipher cipher, int ivLength)
{
super(new IESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
+ new KDF2BytesGenerator(DigestFactory.createSHA1()),
+ new HMac(DigestFactory.createSHA1()),
new PaddedBufferedBlockCipher(cipher)), ivLength);
}
}
- static public class ECIESwithDESede
- extends ECIESwithCipher
- {
- public ECIESwithDESede()
- {
- super(new DESedeEngine());
- }
- }
-
- static public class ECIESwithAES
- extends ECIESwithCipher
- {
- public ECIESwithAES()
- {
- super(new AESEngine());
- }
- }
-
static public class ECIESwithDESedeCBC
extends ECIESwithCipher
{
@@ -565,74 +542,4 @@ public class IESCipher
super(new CBCBlockCipher(new AESEngine()), 16);
}
}
-
- /**
- * Backwards compatibility
- */
- static public class OldECIES
- extends IESCipher
- {
- public OldECIES()
- {
- super(new OldIESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest())));
- }
- }
-
- static public class OldECIESwithCipher
- extends IESCipher
- {
- public OldECIESwithCipher(BlockCipher baseCipher)
- {
- super(new OldIESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(baseCipher)));
- }
-
- public OldECIESwithCipher(BlockCipher baseCipher, int ivLength)
- {
- super(new OldIESEngine(new ECDHBasicAgreement(),
- new KDF2BytesGenerator(new SHA1Digest()),
- new HMac(new SHA1Digest()),
- new PaddedBufferedBlockCipher(baseCipher)), ivLength);
- }
- }
-
- static public class OldECIESwithDESede
- extends OldECIESwithCipher
- {
- public OldECIESwithDESede()
- {
- super(new DESedeEngine());
- }
- }
-
- static public class OldECIESwithAES
- extends OldECIESwithCipher
- {
- public OldECIESwithAES()
- {
- super(new AESEngine());
- }
- }
-
- static public class OldECIESwithDESedeCBC
- extends OldECIESwithCipher
- {
- public OldECIESwithDESedeCBC()
- {
- super(new CBCBlockCipher(new DESedeEngine()), 8);
- }
- }
-
- static public class OldECIESwithAESCBC
- extends OldECIESwithCipher
- {
- public OldECIESwithAESCBC()
- {
- super(new CBCBlockCipher(new AESEngine()), 16);
- }
- }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
index c6a088fb..29d227c6 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -17,17 +17,13 @@ import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.MQVPrivateParameters;
import org.bouncycastle.crypto.params.MQVPublicParameters;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.spec.MQVParameterSpec;
@@ -54,6 +50,7 @@ public class KeyAgreementSpi
private BasicAgreement agreement;
private MQVParameterSpec mqvParameters;
+ private BigInteger result;
protected KeyAgreementSpi(
String kaAlgorithm,
@@ -93,9 +90,9 @@ public class KeyAgreementSpi
if (!(key instanceof MQVPublicKey))
{
ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter((PublicKey)key);
+ ECUtils.generatePublicKeyParameter((PublicKey)key);
ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
+ ECUtils.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
pubKey = new MQVPublicParameters(staticKey, ephemKey);
}
@@ -103,13 +100,11 @@ public class KeyAgreementSpi
{
MQVPublicKey mqvPubKey = (MQVPublicKey)key;
ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ ECUtils.generatePublicKeyParameter(mqvPubKey.getStaticKey());
ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+ ECUtils.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
pubKey = new MQVPublicParameters(staticKey, ephemKey);
-
- // TODO Validate that all the keys are using the same parameters?
}
}
else
@@ -120,12 +115,23 @@ public class KeyAgreementSpi
+ getSimpleName(ECPublicKey.class) + " for doPhase");
}
- pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
-
- // TODO Validate that all the keys are using the same parameters?
+ pubKey = ECUtils.generatePublicKeyParameter((PublicKey)key);
}
- result = agreement.calculateAgreement(pubKey);
+ try
+ {
+ result = agreement.calculateAgreement(pubKey);
+ }
+ catch (final Exception e)
+ {
+ throw new InvalidKeyException("calculation failed: " + e.getMessage())
+ {
+ public Throwable getCause()
+ {
+ return e;
+ }
+ };
+ }
return null;
}
@@ -179,7 +185,7 @@ public class KeyAgreementSpi
if (mqvPrivKey.getEphemeralPublicKey() != null)
{
ephemPubKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ ECUtils.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
}
}
else
@@ -195,7 +201,7 @@ public class KeyAgreementSpi
if (mqvParameterSpec.getEphemeralPublicKey() != null)
{
ephemPubKey = (ECPublicKeyParameters)
- ECUtil.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey());
+ ECUtils.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey());
}
mqvParameters = mqvParameterSpec;
ukmParameters = mqvParameterSpec.getUserKeyingMaterial();
@@ -230,6 +236,12 @@ public class KeyAgreementSpi
return fullName.substring(fullName.lastIndexOf('.') + 1);
}
+
+ protected byte[] calcSecret()
+ {
+ return bigIntToBytes(result);
+ }
+
public static class DH
extends KeyAgreementSpi
{
@@ -262,7 +274,7 @@ public class KeyAgreementSpi
{
public DHwithSHA1KDF()
{
- super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
+ super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
}
}
@@ -271,7 +283,7 @@ public class KeyAgreementSpi
{
public DHwithSHA1KDFAndSharedInfo()
{
- super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
+ super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
}
}
@@ -280,7 +292,7 @@ public class KeyAgreementSpi
{
public CDHwithSHA1KDFAndSharedInfo()
{
- super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
+ super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
}
}
@@ -289,7 +301,7 @@ public class KeyAgreementSpi
{
public DHwithSHA224KDFAndSharedInfo()
{
- super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
+ super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
}
}
@@ -298,7 +310,7 @@ public class KeyAgreementSpi
{
public CDHwithSHA224KDFAndSharedInfo()
{
- super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
+ super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
}
}
@@ -307,7 +319,7 @@ public class KeyAgreementSpi
{
public DHwithSHA256KDFAndSharedInfo()
{
- super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
+ super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
}
}
@@ -316,7 +328,7 @@ public class KeyAgreementSpi
{
public CDHwithSHA256KDFAndSharedInfo()
{
- super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
+ super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
}
}
@@ -325,7 +337,7 @@ public class KeyAgreementSpi
{
public DHwithSHA384KDFAndSharedInfo()
{
- super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
+ super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
}
}
@@ -334,7 +346,7 @@ public class KeyAgreementSpi
{
public CDHwithSHA384KDFAndSharedInfo()
{
- super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
+ super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
}
}
@@ -343,7 +355,7 @@ public class KeyAgreementSpi
{
public DHwithSHA512KDFAndSharedInfo()
{
- super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
+ super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
}
}
@@ -352,7 +364,7 @@ public class KeyAgreementSpi
{
public CDHwithSHA512KDFAndSharedInfo()
{
- super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
+ super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
}
}
@@ -361,7 +373,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA1KDFAndSharedInfo()
{
- super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
+ super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
}
}
@@ -370,7 +382,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA224KDFAndSharedInfo()
{
- super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
+ super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
}
}
@@ -379,7 +391,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA256KDFAndSharedInfo()
{
- super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
+ super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
}
}
@@ -388,7 +400,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA384KDFAndSharedInfo()
{
- super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
+ super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
}
}
@@ -397,7 +409,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA512KDFAndSharedInfo()
{
- super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
+ super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
}
}
@@ -406,7 +418,7 @@ public class KeyAgreementSpi
{
public DHwithSHA1CKDF()
{
- super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest()));
+ super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
}
}
@@ -415,7 +427,7 @@ public class KeyAgreementSpi
{
public DHwithSHA256CKDF()
{
- super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest()));
+ super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
}
}
@@ -424,7 +436,7 @@ public class KeyAgreementSpi
{
public DHwithSHA384CKDF()
{
- super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest()));
+ super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
}
}
@@ -433,7 +445,7 @@ public class KeyAgreementSpi
{
public DHwithSHA512CKDF()
{
- super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest()));
+ super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
}
}
@@ -442,7 +454,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA1CKDF()
{
- super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest()));
+ super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
}
}
@@ -451,7 +463,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA224CKDF()
{
- super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA224Digest()));
+ super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
}
}
@@ -460,7 +472,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA256CKDF()
{
- super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest()));
+ super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
}
}
@@ -469,7 +481,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA384CKDF()
{
- super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest()));
+ super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
}
}
@@ -478,7 +490,7 @@ public class KeyAgreementSpi
{
public MQVwithSHA512CKDF()
{
- super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest()));
+ super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
index 20555c29..243ba51f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -141,13 +141,20 @@ public class KeyFactorySpi
KeySpec keySpec)
throws InvalidKeySpecException
{
- if (keySpec instanceof ECPublicKeySpec)
+ try
{
- return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ }
+ else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+ }
}
- else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ catch (Exception e)
{
- return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+ throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage(), e);
}
return super.engineGeneratePublic(keySpec);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
index b28889d9..62ec75a1 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -8,6 +8,7 @@ import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.util.Hashtable;
+import java.util.Map;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
@@ -181,7 +182,7 @@ public abstract class KeyPairGeneratorSpi
protected ECKeyGenerationParameters createKeyGenParamsBC(ECParameterSpec p, SecureRandom r)
{
- return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), r);
+ return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), r);
}
protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r)
@@ -208,7 +209,14 @@ public abstract class KeyPairGeneratorSpi
p = ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(curveName));
if (p == null)
{
- throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+ Map extraCurves = configuration.getAdditionalECParameters();
+
+ p = (X9ECParameters)extraCurves.get(new ASN1ObjectIdentifier(curveName));
+
+ if (p == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+ }
}
}
catch (IllegalArgumentException ex)
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
index 5e2bb4e4..b8ce0d8b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -17,18 +17,15 @@ import org.bouncycastle.crypto.DSA;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.NullDigest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.crypto.signers.ECNRSigner;
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.bouncycastle.util.Arrays;
public class SignatureSpi
extends DSABase
@@ -41,7 +38,7 @@ public class SignatureSpi
protected void engineInitVerify(PublicKey publicKey)
throws InvalidKeyException
{
- CipherParameters param = ECUtil.generatePublicKeyParameter(publicKey);
+ CipherParameters param = ECUtils.generatePublicKeyParameter(publicKey);
digest.reset();
signer.init(false, param);
@@ -70,7 +67,7 @@ public class SignatureSpi
{
public ecDSA()
{
- super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA1(), new ECDSASigner(), new StdDSAEncoder());
}
}
@@ -79,7 +76,7 @@ public class SignatureSpi
{
public ecDetDSA()
{
- super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder());
+ super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), new StdDSAEncoder());
}
}
@@ -97,7 +94,7 @@ public class SignatureSpi
{
public ecDSA224()
{
- super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA224(), new ECDSASigner(), new StdDSAEncoder());
}
}
@@ -106,7 +103,7 @@ public class SignatureSpi
{
public ecDetDSA224()
{
- super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder());
+ super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), new StdDSAEncoder());
}
}
@@ -115,7 +112,7 @@ public class SignatureSpi
{
public ecDSA256()
{
- super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA256(), new ECDSASigner(), new StdDSAEncoder());
}
}
@@ -124,7 +121,7 @@ public class SignatureSpi
{
public ecDetDSA256()
{
- super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder());
+ super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), new StdDSAEncoder());
}
}
@@ -133,7 +130,7 @@ public class SignatureSpi
{
public ecDSA384()
{
- super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA384(), new ECDSASigner(), new StdDSAEncoder());
}
}
@@ -142,7 +139,7 @@ public class SignatureSpi
{
public ecDetDSA384()
{
- super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder());
+ super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), new StdDSAEncoder());
}
}
@@ -151,7 +148,7 @@ public class SignatureSpi
{
public ecDSA512()
{
- super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA512(), new ECDSASigner(), new StdDSAEncoder());
}
}
@@ -160,7 +157,79 @@ public class SignatureSpi
{
public ecDetDSA512()
{
- super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder());
+ super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSASha3_224
+ extends SignatureSpi
+ {
+ public ecDSASha3_224()
+ {
+ super(DigestFactory.createSHA3_224(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSASha3_224
+ extends SignatureSpi
+ {
+ public ecDetDSASha3_224()
+ {
+ super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSASha3_256
+ extends SignatureSpi
+ {
+ public ecDSASha3_256()
+ {
+ super(DigestFactory.createSHA3_256(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSASha3_256
+ extends SignatureSpi
+ {
+ public ecDetDSASha3_256()
+ {
+ super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSASha3_384
+ extends SignatureSpi
+ {
+ public ecDSASha3_384()
+ {
+ super(DigestFactory.createSHA3_384(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSASha3_384
+ extends SignatureSpi
+ {
+ public ecDetDSASha3_384()
+ {
+ super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSASha3_512
+ extends SignatureSpi
+ {
+ public ecDSASha3_512()
+ {
+ super(DigestFactory.createSHA3_512(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSASha3_512
+ extends SignatureSpi
+ {
+ public ecDetDSASha3_512()
+ {
+ super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), new StdDSAEncoder());
}
}
@@ -178,7 +247,7 @@ public class SignatureSpi
{
public ecNR()
{
- super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA1(), new ECNRSigner(), new StdDSAEncoder());
}
}
@@ -187,7 +256,7 @@ public class SignatureSpi
{
public ecNR224()
{
- super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA224(), new ECNRSigner(), new StdDSAEncoder());
}
}
@@ -196,7 +265,7 @@ public class SignatureSpi
{
public ecNR256()
{
- super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA256(), new ECNRSigner(), new StdDSAEncoder());
}
}
@@ -205,7 +274,7 @@ public class SignatureSpi
{
public ecNR384()
{
- super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA384(), new ECNRSigner(), new StdDSAEncoder());
}
}
@@ -214,7 +283,7 @@ public class SignatureSpi
{
public ecNR512()
{
- super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+ super(DigestFactory.createSHA512(), new ECNRSigner(), new StdDSAEncoder());
}
}
@@ -223,7 +292,7 @@ public class SignatureSpi
{
public ecCVCDSA()
{
- super(new SHA1Digest(), new ECDSASigner(), new PlainDSAEncoder());
+ super(DigestFactory.createSHA1(), new ECDSASigner(), new PlainDSAEncoder());
}
}
@@ -232,7 +301,7 @@ public class SignatureSpi
{
public ecCVCDSA224()
{
- super(new SHA224Digest(), new ECDSASigner(), new PlainDSAEncoder());
+ super(DigestFactory.createSHA224(), new ECDSASigner(), new PlainDSAEncoder());
}
}
@@ -241,7 +310,7 @@ public class SignatureSpi
{
public ecCVCDSA256()
{
- super(new SHA256Digest(), new ECDSASigner(), new PlainDSAEncoder());
+ super(DigestFactory.createSHA256(), new ECDSASigner(), new PlainDSAEncoder());
}
}
@@ -250,7 +319,7 @@ public class SignatureSpi
{
public ecCVCDSA384()
{
- super(new SHA384Digest(), new ECDSASigner(), new PlainDSAEncoder());
+ super(DigestFactory.createSHA384(), new ECDSASigner(), new PlainDSAEncoder());
}
}
@@ -259,7 +328,7 @@ public class SignatureSpi
{
public ecCVCDSA512()
{
- super(new SHA512Digest(), new ECDSASigner(), new PlainDSAEncoder());
+ super(DigestFactory.createSHA512(), new ECDSASigner(), new PlainDSAEncoder());
}
}
@@ -293,6 +362,15 @@ public class SignatureSpi
throws IOException
{
ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ if (s.size() != 2)
+ {
+ throw new IOException("malformed signature");
+ }
+ if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER)))
+ {
+ throw new IOException("malformed signature");
+ }
+
BigInteger[] sig = new BigInteger[2];
sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue();
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
index e1a8449c..c9fa135c 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
@@ -366,12 +366,12 @@ public class BCECGOST3410PrivateKey
curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
}
params = new X962Parameters(curveOid);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS());
}
else if (ecSpec == null)
{
params = new X962Parameters(DERNull.INSTANCE);
- orderBitLength = ECUtil.getOrderBitLength(null, this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, null, this.getS());
}
else
{
@@ -385,7 +385,7 @@ public class BCECGOST3410PrivateKey
ecSpec.getCurve().getSeed());
params = new X962Parameters(ecP);
- orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
+ orderBitLength = ECUtil.getOrderBitLength(BouncyCastleProvider.CONFIGURATION, ecSpec.getOrder(), this.getS());
}
PrivateKeyInfo info;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
index 2d1ffbf9..a2f70818 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
@@ -25,15 +25,15 @@ import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
import org.bouncycastle.jce.interfaces.ECPointEncoder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.math.ec.custom.sec.SecP256K1Point;
-import org.bouncycastle.math.ec.custom.sec.SecP256R1Point;
import org.bouncycastle.util.Strings;
public class BCECGOST3410PublicKey
@@ -44,14 +44,14 @@ public class BCECGOST3410PublicKey
private String algorithm = "ECGOST3410";
private boolean withCompression;
- private transient org.bouncycastle.math.ec.ECPoint q;
+ private transient ECPublicKeyParameters ecPublicKey;
private transient ECParameterSpec ecSpec;
private transient GOST3410PublicKeyAlgParameters gostParams;
public BCECGOST3410PublicKey(
BCECGOST3410PublicKey key)
{
- this.q = key.q;
+ this.ecPublicKey = key.ecPublicKey;
this.ecSpec = key.ecSpec;
this.withCompression = key.withCompression;
this.gostParams = key.gostParams;
@@ -61,29 +61,28 @@ public class BCECGOST3410PublicKey
ECPublicKeySpec spec)
{
this.ecSpec = spec.getParams();
- this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, spec.getParams()));
}
public BCECGOST3410PublicKey(
- org.bouncycastle.jce.spec.ECPublicKeySpec spec)
+ org.bouncycastle.jce.spec.ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
{
- this.q = spec.getQ();
-
if (spec.getParams() != null) // can be null if implictlyCa
{
ECCurve curve = spec.getParams().getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+ // this may seem a little long-winded but it's how we pick up the custom curve.
+ this.ecPublicKey = new ECPublicKeyParameters(
+ spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams()));
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
}
else
{
- if (q.getCurve() == null)
- {
- org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
- q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
- }
+ this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null));
this.ecSpec = null;
}
}
@@ -93,10 +92,10 @@ public class BCECGOST3410PublicKey
ECPublicKeyParameters params,
ECParameterSpec spec)
{
- ECDomainParameters dp = params.getParameters();
+ ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
if (spec == null)
{
@@ -118,7 +117,7 @@ public class BCECGOST3410PublicKey
ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
if (spec == null)
{
@@ -142,7 +141,7 @@ public class BCECGOST3410PublicKey
ECPublicKeyParameters params)
{
this.algorithm = algorithm;
- this.q = params.getQ();
+ this.ecPublicKey = params;
this.ecSpec = null;
}
@@ -162,7 +161,7 @@ public class BCECGOST3410PublicKey
{
this.algorithm = key.getAlgorithm();
this.ecSpec = key.getParams();
- this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(null, key.getParams()));
}
BCECGOST3410PublicKey(
@@ -207,7 +206,7 @@ public class BCECGOST3410PublicKey
ECCurve curve = spec.getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
- this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y));
+ this.ecPublicKey = new ECPublicKeyParameters(curve.createPoint(new BigInteger(1, x), new BigInteger(1, y)), ECUtil.getDomainParameters(null, spec));
ecSpec = new ECNamedCurveSpec(
ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
@@ -260,8 +259,8 @@ public class BCECGOST3410PublicKey
}
}
- BigInteger bX = this.q.getAffineXCoord().toBigInteger();
- BigInteger bY = this.q.getAffineYCoord().toBigInteger();
+ BigInteger bX = this.ecPublicKey.getQ().getAffineXCoord().toBigInteger();
+ BigInteger bY = this.ecPublicKey.getQ().getAffineYCoord().toBigInteger();
byte[] encKey = new byte[64];
extractBytes(encKey, 0, bX);
@@ -312,22 +311,22 @@ public class BCECGOST3410PublicKey
public ECPoint getW()
{
- return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ return new ECPoint(ecPublicKey.getQ().getAffineXCoord().toBigInteger(), ecPublicKey.getQ().getAffineYCoord().toBigInteger());
}
public org.bouncycastle.math.ec.ECPoint getQ()
{
if (ecSpec == null)
{
- return q.getDetachedPoint();
+ return ecPublicKey.getQ().getDetachedPoint();
}
- return q;
+ return ecPublicKey.getQ();
}
- public org.bouncycastle.math.ec.ECPoint engineGetQ()
+ ECPublicKeyParameters engineGetKeyParameters()
{
- return q;
+ return ecPublicKey;
}
org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
@@ -344,10 +343,11 @@ public class BCECGOST3410PublicKey
{
StringBuffer buf = new StringBuffer();
String nl = Strings.lineSeparator();
+ org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
buf.append("EC Public Key").append(nl);
- buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
- buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
return buf.toString();
}
@@ -366,12 +366,12 @@ public class BCECGOST3410PublicKey
BCECGOST3410PublicKey other = (BCECGOST3410PublicKey)o;
- return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
}
public int hashCode()
{
- return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode();
}
private void readObject(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
index 61a34be5..3159cbab 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
@@ -124,7 +124,7 @@ public class KeyFactorySpi
{
if (keySpec instanceof ECPublicKeySpec)
{
- return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec);
+ return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec, BouncyCastleProvider.CONFIGURATION);
}
else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
index efd74b4a..e8e9677e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
@@ -74,7 +74,7 @@ public class KeyPairGeneratorSpi
ECParameterSpec p = (ECParameterSpec)params;
this.ecParams = params;
- param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random);
engine.init(param);
initialised = true;
@@ -134,7 +134,7 @@ public class KeyPairGeneratorSpi
ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
this.ecParams = params;
- param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), random);
engine.init(param);
initialised = true;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
index 407dda57..8c3d9118 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
@@ -14,14 +14,15 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DSA;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.GOST3411Digest;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.ECGOST3410Signer;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util;
import org.bouncycastle.jce.interfaces.ECKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.interfaces.GOST3410Key;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util;
public class SignatureSpi
extends java.security.SignatureSpi
@@ -44,7 +45,7 @@ public class SignatureSpi
if (publicKey instanceof ECPublicKey)
{
- param = ECUtil.generatePublicKeyParameter(publicKey);
+ param = generatePublicKeyParameter(publicKey);
}
else if (publicKey instanceof GOST3410Key)
{
@@ -208,4 +209,11 @@ public class SignatureSpi
{
throw new UnsupportedOperationException("engineSetParameter unsupported");
}
+
+ static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ return (key instanceof BCECGOST3410PublicKey) ? ((BCECGOST3410PublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
index 9c28670b..1cb15488 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
@@ -30,6 +30,7 @@ import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.ElGamalEngine;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
import org.bouncycastle.jce.interfaces.ElGamalKey;
import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
@@ -277,14 +278,8 @@ public class CipherSpi
throws IllegalBlockSizeException, BadPaddingException
{
cipher.processBytes(input, inputOffset, inputLen);
- try
- {
- return cipher.doFinal();
- }
- catch (InvalidCipherTextException e)
- {
- throw new BadPaddingException(e.getMessage());
- }
+
+ return getOutput();
}
protected int engineDoFinal(
@@ -295,18 +290,9 @@ public class CipherSpi
int outputOffset)
throws IllegalBlockSizeException, BadPaddingException
{
- byte[] out;
-
cipher.processBytes(input, inputOffset, inputLen);
- try
- {
- out = cipher.doFinal();
- }
- catch (InvalidCipherTextException e)
- {
- throw new BadPaddingException(e.getMessage());
- }
+ byte[] out = getOutput();
for (int i = 0; i != out.length; i++)
{
@@ -316,6 +302,29 @@ public class CipherSpi
return out.length;
}
+ private byte[] getOutput()
+ throws BadPaddingException
+ {
+ try
+ {
+ return cipher.doFinal();
+ }
+ catch (final InvalidCipherTextException e)
+ {
+ throw new BadPaddingException("unable to decrypt block")
+ {
+ public synchronized Throwable getCause()
+ {
+ return e;
+ }
+ };
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new BadBlockException("unable to decrypt block", e);
+ }
+ }
+
/**
* classes that inherit from us.
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java
index 9da4b58a..d6406a7a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java
@@ -10,8 +10,10 @@ import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.jce.spec.IESParameterSpec;
public class AlgorithmParametersSpi
@@ -46,10 +48,24 @@ public class AlgorithmParametersSpi
{
ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new DEROctetString(currentSpec.getDerivationV()));
- v.add(new DEROctetString(currentSpec.getEncodingV()));
+ if (currentSpec.getDerivationV() != null)
+ {
+ v.add(new DERTaggedObject(false, 0, new DEROctetString(currentSpec.getDerivationV())));
+ }
+ if (currentSpec.getEncodingV() != null)
+ {
+ v.add(new DERTaggedObject(false, 1, new DEROctetString(currentSpec.getEncodingV())));
+ }
v.add(new ASN1Integer(currentSpec.getMacKeySize()));
+ if (currentSpec.getNonce() != null)
+ {
+ ASN1EncodableVector cV = new ASN1EncodableVector();
+ cV.add(new ASN1Integer(currentSpec.getCipherKeySize()));
+ cV.add(new ASN1Integer(currentSpec.getNonce()));
+
+ v.add(new DERSequence(cV));
+ }
return new DERSequence(v).getEncoded(ASN1Encoding.DER);
}
catch (IOException e)
@@ -101,10 +117,40 @@ public class AlgorithmParametersSpi
{
ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
- this.currentSpec = new IESParameterSpec(
- ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
- ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
- ((ASN1Integer)s.getObjectAt(0)).getValue().intValue());
+ if (s.size() == 1)
+ {
+ this.currentSpec = new IESParameterSpec(null, null, ASN1Integer.getInstance(s.getObjectAt(0)).getValue().intValue());
+ }
+ else if (s.size() == 2)
+ {
+ ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(s.getObjectAt(0));
+
+ if (tagged.getTagNo() == 0)
+ {
+ this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged, false).getOctets(), null, ASN1Integer.getInstance(s.getObjectAt(1)).getValue().intValue());
+ }
+ else
+ {
+ this.currentSpec = new IESParameterSpec(null, ASN1OctetString.getInstance(tagged, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(1)).getValue().intValue());
+ }
+ }
+ else if (s.size() == 3)
+ {
+ ASN1TaggedObject tagged1 = ASN1TaggedObject.getInstance(s.getObjectAt(0));
+ ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1));
+
+ this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue());
+ }
+ else if (s.size() == 4)
+ {
+ ASN1TaggedObject tagged1 = ASN1TaggedObject.getInstance(s.getObjectAt(0));
+ ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1));
+ ASN1Sequence cipherDet = ASN1Sequence.getInstance(s.getObjectAt(3));
+
+ this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue(),
+ ASN1Integer.getInstance(cipherDet.getObjectAt(0)).getValue().intValue(),
+ ASN1OctetString.getInstance(cipherDet.getObjectAt(1)).getOctets());
+ }
}
catch (ClassCastException e)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
index de5a9aa5..e60c36ae 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -19,6 +19,7 @@ import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
+import org.bouncycastle.jcajce.util.MessageDigestUtils;
public abstract class AlgorithmParametersSpi
extends java.security.AlgorithmParametersSpi
@@ -118,10 +119,15 @@ public abstract class AlgorithmParametersSpi
{
RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+ if (!oaepP.getMaskGenAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1))
+ {
+ throw new IOException("unknown mask generation function: " + oaepP.getMaskGenAlgorithm().getAlgorithm());
+ }
+
currentSpec = new OAEPParameterSpec(
- oaepP.getHashAlgorithm().getAlgorithm().getId(),
- oaepP.getMaskGenAlgorithm().getAlgorithm().getId(),
- new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ MessageDigestUtils.getDigestName(oaepP.getHashAlgorithm().getAlgorithm()),
+ OAEPParameterSpec.DEFAULT.getMGFAlgorithm(),
+ new MGF1ParameterSpec(MessageDigestUtils.getDigestName(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm())),
new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
}
catch (ClassCastException e)
@@ -133,7 +139,7 @@ public abstract class AlgorithmParametersSpi
throw new IOException("Not a valid OAEP Parameter encoding.");
}
}
-
+
protected void engineInit(
byte[] params,
String format)
@@ -225,10 +231,15 @@ public abstract class AlgorithmParametersSpi
{
RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+ if (!pssP.getMaskGenAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1))
+ {
+ throw new IOException("unknown mask generation function: " + pssP.getMaskGenAlgorithm().getAlgorithm());
+ }
+
currentSpec = new PSSParameterSpec(
- pssP.getHashAlgorithm().getAlgorithm().getId(),
- pssP.getMaskGenAlgorithm().getAlgorithm().getId(),
- new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ MessageDigestUtils.getDigestName(pssP.getHashAlgorithm().getAlgorithm()),
+ PSSParameterSpec.DEFAULT.getMGFAlgorithm(),
+ new MGF1ParameterSpec(MessageDigestUtils.getDigestName(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm())),
pssP.getSaltLength().intValue(),
pssP.getTrailerField().intValue());
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index bbd2a8b4..1edab93e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -32,6 +32,7 @@ import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
@@ -232,6 +233,22 @@ public class CipherSpi
{
initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
}
+ else if (pad.equals("OAEPWITHSHA3-224ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA3-224", "MGF1", new MGF1ParameterSpec("SHA3-224"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA3-256ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA3-256", "MGF1", new MGF1ParameterSpec("SHA3-256"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA3-384ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA3-384", "MGF1", new MGF1ParameterSpec("SHA3-384"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA3-512ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA3-512", "MGF1", new MGF1ParameterSpec("SHA3-512"), PSource.PSpecified.DEFAULT));
+ }
else
{
throw new NoSuchPaddingException(padding + " unavailable with RSA.");
@@ -304,7 +321,7 @@ public class CipherSpi
{
throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
}
-
+
cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
}
}
@@ -462,18 +479,7 @@ public class CipherSpi
}
}
- try
- {
- byte[] bytes = bOut.toByteArray();
-
- bOut.reset();
-
- return cipher.processBlock(bytes, 0, bytes.length);
- }
- catch (InvalidCipherTextException e)
- {
- throw new BadPaddingException(e.getMessage());
- }
+ return getOutput();
}
protected int engineDoFinal(
@@ -504,29 +510,37 @@ public class CipherSpi
}
}
- byte[] out;
+ byte[] out = getOutput();
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+ private byte[] getOutput()
+ throws BadPaddingException
+ {
try
{
byte[] bytes = bOut.toByteArray();
- out = cipher.processBlock(bytes, 0, bytes.length);
+ return cipher.processBlock(bytes, 0, bytes.length);
}
catch (InvalidCipherTextException e)
{
- throw new BadPaddingException(e.getMessage());
+ throw new BadBlockException("unable to decrypt block", e);
}
- finally
+ catch (ArrayIndexOutOfBoundsException e)
{
- bOut.reset();
+ throw new BadBlockException("unable to decrypt block", e);
}
-
- for (int i = 0; i != out.length; i++)
+ finally
{
- output[outputOffset + i] = out[i];
+ bOut.reset();
}
-
- return out.length;
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
index 551bf5a0..6dd055f0 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -25,19 +25,13 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD4Digest;
-import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.NullDigest;
import org.bouncycastle.crypto.digests.RIPEMD128Digest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
import org.bouncycastle.crypto.digests.RIPEMD256Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.digests.SHA512tDigest;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.util.Arrays;
public class DigestSignatureSpi
@@ -255,7 +249,7 @@ public class DigestSignatureSpi
{
public SHA1()
{
- super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(OIWObjectIdentifiers.idSHA1, DigestFactory.createSHA1(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -264,7 +258,7 @@ public class DigestSignatureSpi
{
public SHA224()
{
- super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha224, DigestFactory.createSHA224(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -273,7 +267,7 @@ public class DigestSignatureSpi
{
public SHA256()
{
- super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha256, DigestFactory.createSHA256(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -282,7 +276,7 @@ public class DigestSignatureSpi
{
public SHA384()
{
- super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha384, DigestFactory.createSHA384(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -291,7 +285,7 @@ public class DigestSignatureSpi
{
public SHA512()
{
- super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha512, DigestFactory.createSHA512(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -300,7 +294,7 @@ public class DigestSignatureSpi
{
public SHA512_224()
{
- super(NISTObjectIdentifiers.id_sha512_224, new SHA512tDigest(224), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha512_224, DigestFactory.createSHA512_224(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -309,7 +303,43 @@ public class DigestSignatureSpi
{
public SHA512_256()
{
- super(NISTObjectIdentifiers.id_sha512_256, new SHA512tDigest(256), new PKCS1Encoding(new RSABlindedEngine()));
+ super(NISTObjectIdentifiers.id_sha512_256, DigestFactory.createSHA512_256(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA3_224
+ extends DigestSignatureSpi
+ {
+ public SHA3_224()
+ {
+ super(NISTObjectIdentifiers.id_sha3_224, DigestFactory.createSHA3_224(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA3_256
+ extends DigestSignatureSpi
+ {
+ public SHA3_256()
+ {
+ super(NISTObjectIdentifiers.id_sha3_256, DigestFactory.createSHA3_256(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA3_384
+ extends DigestSignatureSpi
+ {
+ public SHA3_384()
+ {
+ super(NISTObjectIdentifiers.id_sha3_384, DigestFactory.createSHA3_384(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA3_512
+ extends DigestSignatureSpi
+ {
+ public SHA3_512()
+ {
+ super(NISTObjectIdentifiers.id_sha3_512, DigestFactory.createSHA3_512(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
@@ -336,7 +366,7 @@ public class DigestSignatureSpi
{
public MD5()
{
- super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ super(PKCSObjectIdentifiers.md5, DigestFactory.createMD5(), new PKCS1Encoding(new RSABlindedEngine()));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
index 82125b1b..550c5f6e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
@@ -23,6 +23,7 @@ import org.bouncycastle.crypto.digests.SHA512tDigest;
import org.bouncycastle.crypto.digests.WhirlpoolDigest;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.signers.ISO9796d2Signer;
+import org.bouncycastle.crypto.util.DigestFactory;
public class ISOSignatureSpi
extends SignatureSpi
@@ -124,7 +125,7 @@ public class ISOSignatureSpi
{
public SHA1WithRSAEncryption()
{
- super(new SHA1Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA1(), new RSABlindedEngine());
}
}
@@ -133,7 +134,7 @@ public class ISOSignatureSpi
{
public MD5WithRSAEncryption()
{
- super(new MD5Digest(), new RSABlindedEngine());
+ super(DigestFactory.createMD5(), new RSABlindedEngine());
}
}
@@ -151,7 +152,7 @@ public class ISOSignatureSpi
{
public SHA224WithRSAEncryption()
{
- super(new SHA224Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA224(), new RSABlindedEngine());
}
}
@@ -160,7 +161,7 @@ public class ISOSignatureSpi
{
public SHA256WithRSAEncryption()
{
- super(new SHA256Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA256(), new RSABlindedEngine());
}
}
@@ -169,7 +170,7 @@ public class ISOSignatureSpi
{
public SHA384WithRSAEncryption()
{
- super(new SHA384Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA384(), new RSABlindedEngine());
}
}
@@ -178,7 +179,7 @@ public class ISOSignatureSpi
{
public SHA512WithRSAEncryption()
{
- super(new SHA512Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA512(), new RSABlindedEngine());
}
}
@@ -187,7 +188,7 @@ public class ISOSignatureSpi
{
public SHA512_224WithRSAEncryption()
{
- super(new SHA512tDigest(224), new RSABlindedEngine());
+ super(DigestFactory.createSHA512_224(), new RSABlindedEngine());
}
}
@@ -196,7 +197,7 @@ public class ISOSignatureSpi
{
public SHA512_256WithRSAEncryption()
{
- super(new SHA512tDigest(256), new RSABlindedEngine());
+ super(DigestFactory.createSHA512_256(), new RSABlindedEngine());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
index 897e63e6..5532b499 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -347,6 +347,42 @@ public class PSSSignatureSpi
}
}
+ static public class SHA3_224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA3_224withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-224", "MGF1", new MGF1ParameterSpec("SHA3-224"), 28, 1));
+ }
+ }
+
+ static public class SHA3_256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA3_256withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-256", "MGF1", new MGF1ParameterSpec("SHA3-256"), 32, 1));
+ }
+ }
+
+ static public class SHA3_384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA3_384withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-384", "MGF1", new MGF1ParameterSpec("SHA3-384"), 48, 1));
+ }
+ }
+
+ static public class SHA3_512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA3_512withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-512", "MGF1", new MGF1ParameterSpec("SHA3-512"), 64, 1));
+ }
+ }
+
private class NullPssDigest
implements Digest
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java
index bdd22947..c05daefc 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/X931SignatureSpi.java
@@ -14,15 +14,10 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.RIPEMD128Digest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.digests.SHA512tDigest;
import org.bouncycastle.crypto.digests.WhirlpoolDigest;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.signers.X931Signer;
+import org.bouncycastle.crypto.util.DigestFactory;
public class X931SignatureSpi
extends SignatureSpi
@@ -142,7 +137,7 @@ public class X931SignatureSpi
{
public SHA1WithRSAEncryption()
{
- super(new SHA1Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA1(), new RSABlindedEngine());
}
}
@@ -151,7 +146,7 @@ public class X931SignatureSpi
{
public SHA224WithRSAEncryption()
{
- super(new SHA224Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA224(), new RSABlindedEngine());
}
}
@@ -160,7 +155,7 @@ public class X931SignatureSpi
{
public SHA256WithRSAEncryption()
{
- super(new SHA256Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA256(), new RSABlindedEngine());
}
}
@@ -169,7 +164,7 @@ public class X931SignatureSpi
{
public SHA384WithRSAEncryption()
{
- super(new SHA384Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA384(), new RSABlindedEngine());
}
}
@@ -178,7 +173,7 @@ public class X931SignatureSpi
{
public SHA512WithRSAEncryption()
{
- super(new SHA512Digest(), new RSABlindedEngine());
+ super(DigestFactory.createSHA512(), new RSABlindedEngine());
}
}
@@ -187,7 +182,7 @@ public class X931SignatureSpi
{
public SHA512_224WithRSAEncryption()
{
- super(new SHA512tDigest(224), new RSABlindedEngine());
+ super(DigestFactory.createSHA512_224(), new RSABlindedEngine());
}
}
@@ -196,7 +191,7 @@ public class X931SignatureSpi
{
public SHA512_256WithRSAEncryption()
{
- super(new SHA512tDigest(256), new RSABlindedEngine());
+ super(DigestFactory.createSHA512_256(), new RSABlindedEngine());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 8dc0d2dd..3c0800e9 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -1,6 +1,5 @@
package org.bouncycastle.jcajce.provider.asymmetric.util;
-import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Hashtable;
@@ -139,7 +138,6 @@ public abstract class BaseAgreementSpi
private final String kaAlgorithm;
private final DerivationFunction kdf;
- protected BigInteger result;
protected byte[] ukmParameters;
public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
@@ -178,7 +176,7 @@ public abstract class BaseAgreementSpi
{
if (algDetails.indexOf('[') > 0)
{
- return (Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']'))) + 7) / 8;
+ return Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']')));
}
String algKey = Strings.toUpperCase(algDetails);
@@ -221,7 +219,7 @@ public abstract class BaseAgreementSpi
"KDF can only be used when algorithm is known");
}
- return bigIntToBytes(result);
+ return calcSecret();
}
protected int engineGenerateSecret(
@@ -245,7 +243,7 @@ public abstract class BaseAgreementSpi
String algorithm)
throws NoSuchAlgorithmException
{
- byte[] secret = bigIntToBytes(result);
+ byte[] secret = calcSecret();
String algKey = Strings.toUpperCase(algorithm);
String oidAlgorithm = algorithm;
@@ -302,13 +300,15 @@ public abstract class BaseAgreementSpi
}
}
- if (des.containsKey(oidAlgorithm))
+ String algName = getAlgorithm(algorithm);
+
+ if (des.containsKey(algName))
{
DESParameters.setOddParity(secret);
}
- return new SecretKeySpec(secret, getAlgorithm(algorithm));
+ return new SecretKeySpec(secret, algName);
}
- protected abstract byte[] bigIntToBytes(BigInteger result);
+ protected abstract byte[] calcSecret();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
index 482329c2..6747de56 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
@@ -152,9 +152,15 @@ public abstract class BaseCipherSpi
{
throw new InvalidKeyException(e.getMessage());
}
- catch (BadPaddingException e)
+ catch (final BadPaddingException e)
{
- throw new InvalidKeyException(e.getMessage());
+ throw new InvalidKeyException("unable to unwrap")
+ {
+ public synchronized Throwable getCause()
+ {
+ return e;
+ }
+ };
}
catch (IllegalBlockSizeException e2)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
index cb34f447..17c4d3fb 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
@@ -28,12 +28,12 @@ public abstract class BaseKeyFactorySpi
}
catch (Exception e)
{
- throw new InvalidKeySpecException("encoded key spec not recognised");
+ throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage());
}
}
else
{
- throw new InvalidKeySpecException("key spec not recognised");
+ throw new InvalidKeySpecException("key spec not recognized");
}
}
@@ -49,12 +49,12 @@ public abstract class BaseKeyFactorySpi
}
catch (Exception e)
{
- throw new InvalidKeySpecException("encoded key spec not recognised");
+ throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage());
}
}
else
{
- throw new InvalidKeySpecException("key spec not recognised");
+ throw new InvalidKeySpecException("key spec not recognized");
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java
index 52c84ec0..07f8cfd2 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java
@@ -11,6 +11,7 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey;
/**
* utility class for converting jce/jca DH objects
@@ -22,6 +23,10 @@ public class DHUtil
PublicKey key)
throws InvalidKeyException
{
+ if (key instanceof BCDHPublicKey)
+ {
+ return ((BCDHPublicKey)key).engineGetKeyParameters();
+ }
if (key instanceof DHPublicKey)
{
DHPublicKey k = (DHPublicKey)key;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
index 0f25888a..bb357880 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
@@ -10,13 +10,16 @@ import java.security.spec.EllipticCurve;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECAlgorithms;
@@ -43,6 +46,13 @@ public class EC5Util
customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve());
}
}
+
+ X9ECParameters c25519 = CustomNamedCurves.getByName("Curve25519");
+
+ customCurves.put(new ECCurve.Fp(
+ c25519.getCurve().getField().getCharacteristic(),
+ c25519.getCurve().getA().toBigInteger(),
+ c25519.getCurve().getB().toBigInteger()), c25519.getCurve());
}
public static ECCurve getCurve(
@@ -50,28 +60,66 @@ public class EC5Util
X962Parameters params)
{
ECCurve curve;
+ Set acceptableCurves = configuration.getAcceptableNamedCurves();
if (params.isNamedCurve())
{
ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
- X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
- curve = ecP.getCurve();
+ if (acceptableCurves.isEmpty() || acceptableCurves.contains(oid))
+ {
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = (X9ECParameters)configuration.getAdditionalECParameters().get(oid);
+ }
+
+ curve = ecP.getCurve();
+ }
+ else
+ {
+ throw new IllegalStateException("named curve not acceptable");
+ }
}
else if (params.isImplicitlyCA())
{
curve = configuration.getEcImplicitlyCa().getCurve();
}
- else
+ else if (acceptableCurves.isEmpty())
{
X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
curve = ecP.getCurve();
}
+ else
+ {
+ throw new IllegalStateException("encoded parameters not acceptable");
+ }
return curve;
}
+ public static ECDomainParameters getDomainParameters(
+ ProviderConfiguration configuration,
+ java.security.spec.ECParameterSpec params)
+ {
+ ECDomainParameters domainParameters;
+
+ if (params == null)
+ {
+ org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+ domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+ }
+ else
+ {
+ domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params, false));
+ }
+
+ return domainParameters;
+ }
+
public static ECParameterSpec convertToSpec(
X962Parameters params, ECCurve curve)
{
@@ -82,6 +130,14 @@ public class EC5Util
{
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+ if (ecP == null)
+ {
+ Map additionalECParameters = BouncyCastleProvider.CONFIGURATION.getAdditionalECParameters();
+ if (!additionalECParameters.isEmpty())
+ {
+ ecP = (X9ECParameters)additionalECParameters.get(oid);
+ }
+ }
ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
index 465e621f..7542dba8 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
@@ -5,6 +5,7 @@ import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Enumeration;
+import java.util.Map;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.anssi.ANSSINamedCurves;
@@ -16,16 +17,19 @@ import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
/**
@@ -104,6 +108,67 @@ public class ECUtil
return res;
}
+ public static ECDomainParameters getDomainParameters(
+ ProviderConfiguration configuration,
+ org.bouncycastle.jce.spec.ECParameterSpec params)
+ {
+ ECDomainParameters domainParameters;
+
+ if (params instanceof ECNamedCurveParameterSpec)
+ {
+ ECNamedCurveParameterSpec nParams = (ECNamedCurveParameterSpec)params;
+ ASN1ObjectIdentifier nameOid = ECUtil.getNamedCurveOid(nParams.getName());
+
+ domainParameters = new ECNamedDomainParameters(nameOid, nParams.getCurve(), nParams.getG(), nParams.getN(), nParams.getH(), nParams.getSeed());
+ }
+ else if (params == null)
+ {
+ org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+ domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+ }
+ else
+ {
+ domainParameters = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed());
+ }
+
+ return domainParameters;
+ }
+
+ public static ECDomainParameters getDomainParameters(
+ ProviderConfiguration configuration,
+ X962Parameters params)
+ {
+ ECDomainParameters domainParameters;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+ if (ecP == null)
+ {
+ Map extraCurves = configuration.getAdditionalECParameters();
+
+ ecP = (X9ECParameters)extraCurves.get(oid);
+ }
+ domainParameters = new ECNamedDomainParameters(oid, ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+ domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+ domainParameters = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
+ }
+
+ return domainParameters;
+ }
+
public static AsymmetricKeyParameter generatePublicKeyParameter(
PublicKey key)
throws InvalidKeyException
@@ -113,20 +178,9 @@ public class ECUtil
ECPublicKey k = (ECPublicKey)key;
ECParameterSpec s = k.getParameters();
- if (s == null)
- {
- s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
-
- return new ECPublicKeyParameters(
- ((BCECPublicKey)k).engineGetQ(),
- new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
- }
- else
- {
- return new ECPublicKeyParameters(
+ return new ECPublicKeyParameters(
k.getQ(),
new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
- }
}
else if (key instanceof java.security.interfaces.ECPublicKey)
{
@@ -218,11 +272,11 @@ public class ECUtil
throw new InvalidKeyException("can't identify EC private key.");
}
- public static int getOrderBitLength(BigInteger order, BigInteger privateValue)
+ public static int getOrderBitLength(ProviderConfiguration configuration, BigInteger order, BigInteger privateValue)
{
if (order == null) // implicitly CA
{
- ECParameterSpec implicitCA = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ ECParameterSpec implicitCA = configuration.getEcImplicitlyCa();
if (implicitCA == null)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java
index 67396de3..63373b24 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/IESUtil.java
@@ -6,7 +6,7 @@ import org.bouncycastle.jce.spec.IESParameterSpec;
public class IESUtil
{
- public static IESParameterSpec guessParameterSpec(BufferedBlockCipher iesBlockCipher)
+ public static IESParameterSpec guessParameterSpec(BufferedBlockCipher iesBlockCipher, byte[] nonce)
{
if (iesBlockCipher == null)
{
@@ -21,18 +21,18 @@ public class IESUtil
underlyingCipher.getAlgorithmName().equals("RC5-32") ||
underlyingCipher.getAlgorithmName().equals("RC5-64"))
{
- return new IESParameterSpec(null, null, 64, 64);
+ return new IESParameterSpec(null, null, 64, 64, nonce);
}
else if (underlyingCipher.getAlgorithmName().equals("SKIPJACK"))
{
- return new IESParameterSpec(null, null, 80, 80);
+ return new IESParameterSpec(null, null, 80, 80, nonce);
}
else if (underlyingCipher.getAlgorithmName().equals("GOST28147"))
{
- return new IESParameterSpec(null, null, 256, 256);
+ return new IESParameterSpec(null, null, 256, 256, nonce);
}
- return new IESParameterSpec(null, null, 128, 128);
+ return new IESParameterSpec(null, null, 128, 128, nonce);
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
index 2203ce79..9bd1bf0b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -1,5 +1,7 @@
package org.bouncycastle.jcajce.provider.asymmetric.x509;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
@@ -26,6 +28,7 @@ import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificateList;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
+import org.bouncycastle.util.io.Streams;
/**
* class for dealing with X509 certificates.
@@ -200,7 +203,18 @@ public class CertificateFactory
}
}
- PushbackInputStream pis = new PushbackInputStream(in);
+ InputStream pis;
+
+ if (in.markSupported())
+ {
+ pis = in;
+ }
+ else
+ {
+ pis = new ByteArrayInputStream(Streams.readAll(in));
+ }
+
+ pis.mark(1);
int tag = pis.read();
if (tag == -1)
@@ -208,8 +222,7 @@ public class CertificateFactory
return null;
}
- pis.unread(tag);
-
+ pis.reset();
if (tag != 0x30) // assume ascii PEM encoded.
{
return readPEMCertificate(pis);
@@ -234,9 +247,11 @@ public class CertificateFactory
throws CertificateException
{
java.security.cert.Certificate cert;
+ BufferedInputStream in = new BufferedInputStream(inStream);
+
List certs = new ArrayList();
- while ((cert = engineGenerateCertificate(inStream)) != null)
+ while ((cert = engineGenerateCertificate(in)) != null)
{
certs.add(cert);
}
@@ -249,18 +264,18 @@ public class CertificateFactory
* it with the data read from the input stream inStream.
*/
public CRL engineGenerateCRL(
- InputStream inStream)
+ InputStream in)
throws CRLException
{
if (currentCrlStream == null)
{
- currentCrlStream = inStream;
+ currentCrlStream = in;
sCrlData = null;
sCrlDataObjectCount = 0;
}
- else if (currentCrlStream != inStream) // reset if input stream has changed
+ else if (currentCrlStream != in) // reset if input stream has changed
{
- currentCrlStream = inStream;
+ currentCrlStream = in;
sCrlData = null;
sCrlDataObjectCount = 0;
}
@@ -281,7 +296,18 @@ public class CertificateFactory
}
}
- PushbackInputStream pis = new PushbackInputStream(inStream);
+ InputStream pis;
+
+ if (in.markSupported())
+ {
+ pis = in;
+ }
+ else
+ {
+ pis = new ByteArrayInputStream(Streams.readAll(in));
+ }
+
+ pis.mark(1);
int tag = pis.read();
if (tag == -1)
@@ -289,8 +315,7 @@ public class CertificateFactory
return null;
}
- pis.unread(tag);
-
+ pis.reset();
if (tag != 0x30) // assume ascii PEM encoded.
{
return readPEMCRL(pis);
@@ -325,8 +350,9 @@ public class CertificateFactory
{
CRL crl;
List crls = new ArrayList();
+ BufferedInputStream in = new BufferedInputStream(inStream);
- while ((crl = engineGenerateCRL(inStream)) != null)
+ while ((crl = engineGenerateCRL(in)) != null)
{
crls.add(crl);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
index 8116f294..3efd2d69 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
@@ -43,6 +43,22 @@ class PEMUtil
return null;
}
+ // make sure we parse to end of line.
+ if (c == '\r')
+ {
+ // a '\n' may follow
+ in.mark(1);
+ if (((c = in.read()) == '\n'))
+ {
+ in.mark(1);
+ }
+
+ if (c > 0)
+ {
+ in.reset();
+ }
+ }
+
return l.toString();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 8488f808..d94dd16f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -16,20 +16,17 @@ import org.bouncycastle.asn1.ASN1Null;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.util.MessageDigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
class X509SignatureUtil
{
private static final ASN1Null derNull = DERNull.INSTANCE;
-
+
static void setSignatureParameters(
Signature signature,
ASN1Encodable params)
@@ -119,49 +116,14 @@ class X509SignatureUtil
private static String getDigestAlgName(
ASN1ObjectIdentifier digestAlgOID)
{
- if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
- {
- return "MD5";
- }
- else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
- {
- return "SHA1";
- }
- else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
- {
- return "SHA224";
- }
- else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
- {
- return "SHA256";
- }
- else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
- {
- return "SHA384";
- }
- else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
- {
- return "SHA512";
- }
- else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
- {
- return "RIPEMD128";
- }
- else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
- {
- return "RIPEMD160";
- }
- else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
- {
- return "RIPEMD256";
- }
- else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
- {
- return "GOST3411";
- }
- else
+ String name = MessageDigestUtils.getDigestName(digestAlgOID);
+
+ int dIndex = name.indexOf('-');
+ if (dIndex > 0 && !name.startsWith("SHA3"))
{
- return digestAlgOID.getId();
+ return name.substring(0, dIndex) + name.substring(dIndex + 1);
}
+
+ return MessageDigestUtils.getDigestName(digestAlgOID);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
index 5fb3ffc9..0865b576 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -29,6 +29,16 @@ public interface ConfigurableProvider
*/
static final String DH_DEFAULT_PARAMS = "DhDefaultParams";
+ /**
+ * A set of OBJECT IDENTIFIERs representing acceptable named curves for imported keys.
+ */
+ static final String ACCEPTABLE_EC_CURVES = "acceptableEcCurves";
+
+ /**
+ * A set of OBJECT IDENTIFIERs to EC Curves providing local curve name mapping.
+ */
+ static final String ADDITIONAL_EC_PARAMETERS = "additionalEcParameters";
+
void setParameter(String parameterName, Object parameter);
void addAlgorithm(String key, String value);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
index 2d99ed9b..e293d9f7 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
@@ -1,5 +1,8 @@
package org.bouncycastle.jcajce.provider.config;
+import java.util.Map;
+import java.util.Set;
+
import javax.crypto.spec.DHParameterSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
@@ -9,4 +12,8 @@ public interface ProviderConfiguration
ECParameterSpec getEcImplicitlyCa();
DHParameterSpec getDHDefaultParameters(int keySize);
+
+ Set getAcceptableNamedCurves();
+
+ Map getAdditionalECParameters();
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
index b21afc54..8d937877 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
@@ -27,18 +27,23 @@ import org.bouncycastle.util.Strings;
public class ProviderConfigurationPermission
extends BasicPermission
{
- private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
- private static final int EC_IMPLICITLY_CA = 0x02;
- private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
- private static final int DH_DEFAULT_PARAMS = 0x08;
+ private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
+ private static final int EC_IMPLICITLY_CA = 0x02;
+ private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
+ private static final int DH_DEFAULT_PARAMS = 0x08;
+ private static final int ACCEPTABLE_EC_CURVES = 0x10;
+ private static final int ADDITIONAL_EC_PARAMETERS = 0x20;
- private static final int ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS;
+ private static final int ALL =
+ THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS |
+ ACCEPTABLE_EC_CURVES | ADDITIONAL_EC_PARAMETERS;
private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca";
private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca";
private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams";
private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams";
-
+ private static final String ACCEPTABLE_EC_CURVES_STR = "acceptableeccurves";
+ private static final String ADDITIONAL_EC_PARAMETERS_STR = "additionalecparameters";
private static final String ALL_STR = "all";
private final String actions;
@@ -84,6 +89,14 @@ public class ProviderConfigurationPermission
{
mask |= DH_DEFAULT_PARAMS;
}
+ else if (s.equals(ACCEPTABLE_EC_CURVES_STR))
+ {
+ mask |= ACCEPTABLE_EC_CURVES;
+ }
+ else if (s.equals(ADDITIONAL_EC_PARAMETERS_STR))
+ {
+ mask |= ADDITIONAL_EC_PARAMETERS;
+ }
else if (s.equals(ALL_STR))
{
mask |= ALL;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
index 2112673e..6d5dfa3d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
@@ -1,8 +1,11 @@
package org.bouncycastle.jcajce.provider.digest;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.GOST3411Digest;
+import org.bouncycastle.crypto.digests.GOST3411_2012_256Digest;
+import org.bouncycastle.crypto.digests.GOST3411_2012_512Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
@@ -35,6 +38,44 @@ public class GOST3411
}
}
+ static public class Digest2012_256
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest2012_256()
+ {
+ super(new GOST3411_2012_256Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest2012_256 d = (Digest2012_256)super.clone();
+ d.digest = new GOST3411_2012_256Digest((GOST3411_2012_256Digest)digest);
+
+ return d;
+ }
+ }
+
+ static public class Digest2012_512
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest2012_512()
+ {
+ super(new GOST3411_2012_512Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest2012_512 d = (Digest2012_512)super.clone();
+ d.digest = new GOST3411_2012_512Digest((GOST3411_2012_512Digest)digest);
+
+ return d;
+ }
+ }
+
/**
* GOST3411 HMac
*/
@@ -47,6 +88,24 @@ public class GOST3411
}
}
+ public static class HashMac2012_256
+ extends BaseMac
+ {
+ public HashMac2012_256()
+ {
+ super(new HMac(new GOST3411_2012_256Digest()));
+ }
+ }
+
+ public static class HashMac2012_512
+ extends BaseMac
+ {
+ public HashMac2012_512()
+ {
+ super(new HMac(new GOST3411_2012_512Digest()));
+ }
+ }
+
/**
* PBEWithHmacGOST3411
*/
@@ -68,6 +127,24 @@ public class GOST3411
}
}
+ public static class KeyGenerator2012_256
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator2012_256()
+ {
+ super("HMACGOST3411", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGenerator2012_512
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator2012_512()
+ {
+ super("HMACGOST3411", 512, new CipherKeyGenerator());
+ }
+ }
+
public static class Mappings
extends DigestAlgorithmProvider
{
@@ -84,11 +161,27 @@ public class GOST3411
provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
provider.addAlgorithm("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
- provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACGOST3411", PREFIX + "$PBEWithMacKeyFactory");
- provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + CryptoProObjectIdentifiers.gostR3411, "PBEWITHHMACGOST3411");
-
addHMACAlgorithm(provider, "GOST3411", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
addHMACAlias(provider, "GOST3411", CryptoProObjectIdentifiers.gostR3411);
+
+ provider.addAlgorithm("MessageDigest.GOST3411-2012-256", PREFIX + "$Digest2012_256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-2012-256", "GOST3411-2012-256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-3411-2012-256", "GOST3411-2012-256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256, "GOST3411-2012-256");
+
+ addHMACAlgorithm(provider, "GOST3411-2012-256", PREFIX + "$HashMac2012_256", PREFIX + "$KeyGenerator2012_256");
+ addHMACAlias(provider, "GOST3411-2012-256", RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256);
+
+ provider.addAlgorithm("MessageDigest.GOST3411-2012-512", PREFIX + "$Digest2012_512");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-2012-512", "GOST3411-2012-512");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-3411-2012-512", "GOST3411-2012-512");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512, "GOST3411-2012-512");
+
+ addHMACAlgorithm(provider, "GOST3411-2012-512", PREFIX + "$HashMac2012_512", PREFIX + "$KeyGenerator2012_512");
+ addHMACAlias(provider, "GOST3411-2012-512", RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512);
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACGOST3411", PREFIX + "$PBEWithMacKeyFactory");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + CryptoProObjectIdentifiers.gostR3411, "PBEWITHHMACGOST3411");
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
index 1fdadc24..17a5462a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -1,24 +1,14 @@
package org.bouncycastle.jcajce.provider.digest;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.PBEKeySpec;
-
import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
-import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
-import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
-import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
public class SHA1
@@ -92,79 +82,6 @@ public class SHA1
}
}
-
- public static class BasePBKDF2WithHmacSHA1
- extends BaseSecretKeyFactory
- {
- private int scheme;
-
- public BasePBKDF2WithHmacSHA1(String name, int scheme)
- {
- super(name, PKCSObjectIdentifiers.id_PBKDF2);
-
- this.scheme = scheme;
- }
-
- protected SecretKey engineGenerateSecret(
- KeySpec keySpec)
- throws InvalidKeySpecException
- {
- if (keySpec instanceof PBEKeySpec)
- {
- PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
-
- if (pbeSpec.getSalt() == null)
- {
- throw new InvalidKeySpecException("missing required salt");
- }
-
- if (pbeSpec.getIterationCount() <= 0)
- {
- throw new InvalidKeySpecException("positive iteration count required: "
- + pbeSpec.getIterationCount());
- }
-
- if (pbeSpec.getKeyLength() <= 0)
- {
- throw new InvalidKeySpecException("positive key length required: "
- + pbeSpec.getKeyLength());
- }
-
- if (pbeSpec.getPassword().length == 0)
- {
- throw new IllegalArgumentException("password empty");
- }
-
- int digest = SHA1;
- int keySize = pbeSpec.getKeyLength();
- int ivSize = -1; // JDK 1,2 and earlier does not understand simplified version.
- CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
-
- return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
- }
-
- throw new InvalidKeySpecException("Invalid KeySpec");
- }
- }
-
- public static class PBKDF2WithHmacSHA1UTF8
- extends BasePBKDF2WithHmacSHA1
- {
- public PBKDF2WithHmacSHA1UTF8()
- {
- super("PBKDF2WithHmacSHA1", PKCS5S2_UTF8);
- }
- }
-
- public static class PBKDF2WithHmacSHA18BIT
- extends BasePBKDF2WithHmacSHA1
- {
- public PBKDF2WithHmacSHA18BIT()
- {
- super("PBKDF2WithHmacSHA1And8bit", PKCS5S2);
- }
- }
-
public static class Mappings
extends DigestAlgorithmProvider
{
@@ -192,11 +109,6 @@ public class SHA1
provider.addAlgorithm("Alg.Alias.Mac." + OIWObjectIdentifiers.idSHA1, "PBEWITHHMACSHA");
provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA1", PREFIX + "$PBEWithMacKeyFactory");
- provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
- provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
- provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
- provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2withASCII", "PBKDF2WithHmacSHA1And8BIT");
- provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2with8BIT", "PBKDF2WithHmacSHA1And8BIT");
- }
+ }
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
index ba06a0fb..ac83fc23 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -68,6 +68,8 @@ public class SHA224
provider.addAlgorithm("Alg.Alias.MessageDigest.SHA224", "SHA-224");
provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA224", PREFIX + "$HashMac");
+
addHMACAlgorithm(provider, "SHA224", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
index 785cf655..e203362f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -88,6 +88,8 @@ public class SHA256
provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA-256", "PBEWITHHMACSHA256");
provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + NISTObjectIdentifiers.id_sha256, "PBEWITHHMACSHA256");
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA256", PREFIX + "$HashMac");
+
addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA3.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA3.java
index 582f7725..8f048b10 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA3.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA3.java
@@ -1,8 +1,12 @@
package org.bouncycastle.jcajce.provider.digest;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
public class SHA3
{
@@ -30,6 +34,24 @@ public class SHA3
}
}
+ public static class HashMacSHA3
+ extends BaseMac
+ {
+ public HashMacSHA3(int size)
+ {
+ super(new HMac(new SHA3Digest(size)));
+ }
+ }
+
+ public static class KeyGeneratorSHA3
+ extends BaseKeyGenerator
+ {
+ public KeyGeneratorSHA3(int size)
+ {
+ super("HMACSHA3-" + size, size, new CipherKeyGenerator());
+ }
+ }
+
static public class Digest224
extends DigestSHA3
{
@@ -66,6 +88,78 @@ public class SHA3
}
}
+ static public class HashMac224
+ extends HashMacSHA3
+ {
+ public HashMac224()
+ {
+ super(224);
+ }
+ }
+
+ static public class HashMac256
+ extends HashMacSHA3
+ {
+ public HashMac256()
+ {
+ super(256);
+ }
+ }
+
+ static public class HashMac384
+ extends HashMacSHA3
+ {
+ public HashMac384()
+ {
+ super(384);
+ }
+ }
+
+ static public class HashMac512
+ extends HashMacSHA3
+ {
+ public HashMac512()
+ {
+ super(512);
+ }
+ }
+
+ static public class KeyGenerator224
+ extends KeyGeneratorSHA3
+ {
+ public KeyGenerator224()
+ {
+ super(224);
+ }
+ }
+
+ static public class KeyGenerator256
+ extends KeyGeneratorSHA3
+ {
+ public KeyGenerator256()
+ {
+ super(256);
+ }
+ }
+
+ static public class KeyGenerator384
+ extends KeyGeneratorSHA3
+ {
+ public KeyGenerator384()
+ {
+ super(384);
+ }
+ }
+
+ static public class KeyGenerator512
+ extends KeyGeneratorSHA3
+ {
+ public KeyGenerator512()
+ {
+ super(512);
+ }
+ }
+
public static class Mappings
extends DigestAlgorithmProvider
{
@@ -85,6 +179,18 @@ public class SHA3
provider.addAlgorithm("MessageDigest", NISTObjectIdentifiers.id_sha3_256, PREFIX + "$Digest256");
provider.addAlgorithm("MessageDigest", NISTObjectIdentifiers.id_sha3_384, PREFIX + "$Digest384");
provider.addAlgorithm("MessageDigest", NISTObjectIdentifiers.id_sha3_512, PREFIX + "$Digest512");
+
+ addHMACAlgorithm(provider, "SHA3-224", PREFIX + "$HashMac224", PREFIX + "$KeyGenerator224");
+ addHMACAlias(provider, "SHA3-224", NISTObjectIdentifiers.id_hmacWithSHA3_224);
+
+ addHMACAlgorithm(provider, "SHA3-256", PREFIX + "$HashMac256", PREFIX + "$KeyGenerator256");
+ addHMACAlias(provider, "SHA3-256", NISTObjectIdentifiers.id_hmacWithSHA3_256);
+
+ addHMACAlgorithm(provider, "SHA3-384", PREFIX + "$HashMac384", PREFIX + "$KeyGenerator384");
+ addHMACAlias(provider, "SHA3-384", NISTObjectIdentifiers.id_hmacWithSHA3_384);
+
+ addHMACAlgorithm(provider, "SHA3-512", PREFIX + "$HashMac512", PREFIX + "$KeyGenerator512");
+ addHMACAlias(provider, "SHA3-512", NISTObjectIdentifiers.id_hmacWithSHA3_512);
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
index f811df66..75b04ebf 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -82,6 +82,8 @@ public class SHA384
provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
provider.addAlgorithm("Mac.OLDHMACSHA384", PREFIX + "$OldSHA384");
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA384", PREFIX + "$HashMac");
+
addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
index 48adf738..01371e7f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -168,6 +168,8 @@ public class SHA512
provider.addAlgorithm("Mac.OLDHMACSHA512", PREFIX + "$OldSHA512");
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA512", PREFIX + "$HashMac");
+
addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java
new file mode 100644
index 00000000..b33c3054
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java
@@ -0,0 +1,199 @@
+package org.bouncycastle.jcajce.provider.drbg;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.SecureRandomSpi;
+
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.prng.EntropySource;
+import org.bouncycastle.crypto.prng.EntropySourceProvider;
+import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
+import org.bouncycastle.util.Strings;
+
+public class DRBG
+{
+ private static final String PREFIX = DRBG.class.getName();
+
+ // {"Provider class name","SecureRandomSpi class name"}
+ private static final String[][] initialEntropySourceNames = new String[][]
+ {
+ // Normal JVM
+ {"sun.security.provider.Sun", "sun.security.provider.SecureRandom"},
+ // Apache harmony
+ {"org.apache.harmony.security.provider.crypto.CryptoProvider", "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl"},
+ // Android.
+ {"com.android.org.conscrypt.OpenSSLProvider", "com.android.org.conscrypt.OpenSSLRandom"},
+ {"org.conscrypt.OpenSSLProvider", "org.conscrypt.OpenSSLRandom"},
+ };
+
+ private static final Object[] initialEntropySourceAndSpi = findSource();
+
+ // Cascade through providers looking for match.
+ private final static Object[] findSource()
+ {
+ for (int t = 0; t < initialEntropySourceNames.length; t++)
+ {
+ String[] pair = initialEntropySourceNames[t];
+ try
+ {
+ Object[] r = new Object[]{Class.forName(pair[0]).newInstance(), Class.forName(pair[1]).newInstance()};
+
+ return r;
+ }
+ catch (Throwable ex)
+ {
+ continue;
+ }
+ }
+
+ return null;
+ }
+
+ private static class CoreSecureRandom
+ extends SecureRandom
+ {
+ CoreSecureRandom()
+ {
+ super((SecureRandomSpi)initialEntropySourceAndSpi[1], (Provider)initialEntropySourceAndSpi[0]);
+ }
+ }
+
+ // unfortunately new SecureRandom() can cause a regress and it's the only reliable way of getting access
+ // to the JVM's seed generator.
+ private static SecureRandom createInitialEntropySource()
+ {
+ if (initialEntropySourceAndSpi != null)
+ {
+ return new CoreSecureRandom();
+ }
+ else
+ {
+ return new SecureRandom(); // we're desperate, it's worth a try.
+ }
+ }
+
+ private static EntropySourceProvider createEntropySource()
+ {
+ final String sourceClass = System.getProperty("org.bouncycastle.drbg.entropysource");
+
+ return AccessController.doPrivileged(new PrivilegedAction<EntropySourceProvider>()
+ {
+ public EntropySourceProvider run()
+ {
+ try
+ {
+ Class clazz = DRBG.class.getClassLoader().loadClass(sourceClass);
+
+ return (EntropySourceProvider)clazz.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("entropy source " + sourceClass + " not created: " + e.getMessage(), e);
+ }
+ }
+ });
+ }
+
+ private static SecureRandom createBaseRandom(boolean isPredictionResistant)
+ {
+ if (System.getProperty("org.bouncycastle.drbg.entropysource") != null)
+ {
+ EntropySourceProvider entropyProvider = createEntropySource();
+
+ EntropySource initSource = entropyProvider.get(16 * 8);
+
+ return new SP800SecureRandomBuilder(entropyProvider)
+ .setPersonalizationString(generateDefaultPersonalizationString(initSource.getEntropy()))
+ .buildHash(new SHA512Digest(), Arrays.concatenate(initSource.getEntropy(), initSource.getEntropy()), isPredictionResistant);
+ }
+ else
+ {
+ SecureRandom randomSource = createInitialEntropySource(); // needs to be done late, can't use static
+ return new SP800SecureRandomBuilder(randomSource, true)
+ .setPersonalizationString(generateDefaultPersonalizationString(randomSource.generateSeed(16)))
+ .buildHash(new SHA512Digest(), randomSource.generateSeed(32), isPredictionResistant);
+ }
+ }
+
+ public static class Default
+ extends SecureRandomSpi
+ {
+ private static final SecureRandom random = createBaseRandom(true);
+
+ public Default()
+ {
+ }
+
+ protected void engineSetSeed(byte[] bytes)
+ {
+ random.setSeed(bytes);
+ }
+
+ protected void engineNextBytes(byte[] bytes)
+ {
+ random.nextBytes(bytes);
+ }
+
+ protected byte[] engineGenerateSeed(int numBytes)
+ {
+ return random.generateSeed(numBytes);
+ }
+ }
+
+ public static class NonceAndIV
+ extends SecureRandomSpi
+ {
+ private static final SecureRandom random = createBaseRandom(false);
+
+ public NonceAndIV()
+ {
+ }
+
+ protected void engineSetSeed(byte[] bytes)
+ {
+ random.setSeed(bytes);
+ }
+
+ protected void engineNextBytes(byte[] bytes)
+ {
+ random.nextBytes(bytes);
+ }
+
+ protected byte[] engineGenerateSeed(int numBytes)
+ {
+ return random.generateSeed(numBytes);
+ }
+ }
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("SecureRandom.DEFAULT", PREFIX + "$Default");
+ provider.addAlgorithm("SecureRandom.NONCEANDIV", PREFIX + "$NonceAndIV");
+ }
+ }
+
+ private static byte[] generateDefaultPersonalizationString(byte[] seed)
+ {
+ return Arrays.concatenate(Strings.toByteArray("Default"), seed,
+ Pack.longToBigEndian(Thread.currentThread().getId()), Pack.longToBigEndian(System.currentTimeMillis()));
+ }
+
+ private static byte[] generateNonceIVPersonalizationString(byte[] seed)
+ {
+ return Arrays.concatenate(Strings.toByteArray("Nonce"), seed,
+ Pack.longToLittleEndian(Thread.currentThread().getId()), Pack.longToLittleEndian(System.currentTimeMillis()));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java
new file mode 100644
index 00000000..9eb290a3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/BCFKS.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.jcajce.provider.keystore;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class BCFKS
+{
+ private static final String PREFIX = "org.bouncycastle.jcajce.provider.keystore" + ".bcfks.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyStore.BCFKS", PREFIX + "BcFKSKeyStoreSpi$Std");
+ provider.addAlgorithm("KeyStore.BCFKS-DEF", PREFIX + "BcFKSKeyStoreSpi$Def");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
new file mode 100644
index 00000000..fdf886ba
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -0,0 +1,973 @@
+package org.bouncycastle.jcajce.provider.keystore.bcfks;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.bc.EncryptedObjectStoreData;
+import org.bouncycastle.asn1.bc.EncryptedPrivateKeyData;
+import org.bouncycastle.asn1.bc.EncryptedSecretKeyData;
+import org.bouncycastle.asn1.bc.ObjectData;
+import org.bouncycastle.asn1.bc.ObjectDataSequence;
+import org.bouncycastle.asn1.bc.ObjectStore;
+import org.bouncycastle.asn1.bc.ObjectStoreData;
+import org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck;
+import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
+import org.bouncycastle.asn1.bc.SecretKeyData;
+import org.bouncycastle.asn1.cms.CCMParameters;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.EncryptionScheme;
+import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
+import org.bouncycastle.asn1.pkcs.PBES2Parameters;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+class BcFKSKeyStoreSpi
+ extends KeyStoreSpi
+{
+ private static final Map<String, ASN1ObjectIdentifier> oidMap = new HashMap<String, ASN1ObjectIdentifier>();
+ private static final Map<ASN1ObjectIdentifier, String> publicAlgMap = new HashMap<ASN1ObjectIdentifier, String>();
+
+ static
+ {
+ // Note: AES handled inline
+ oidMap.put("DESEDE", OIWObjectIdentifiers.desEDE);
+ oidMap.put("TRIPLEDES", OIWObjectIdentifiers.desEDE);
+ oidMap.put("TDEA", OIWObjectIdentifiers.desEDE);
+ oidMap.put("HMACSHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+ oidMap.put("HMACSHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
+ oidMap.put("HMACSHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+ oidMap.put("HMACSHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+ oidMap.put("HMACSHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+
+ publicAlgMap.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ publicAlgMap.put(X9ObjectIdentifiers.id_ecPublicKey, "EC");
+ publicAlgMap.put(OIWObjectIdentifiers.elGamalAlgorithm, "DH");
+ publicAlgMap.put(PKCSObjectIdentifiers.dhKeyAgreement, "DH");
+ publicAlgMap.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ private static String getPublicKeyAlg(ASN1ObjectIdentifier oid)
+ {
+ String algName = (String)publicAlgMap.get(oid);
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return oid.getId();
+ }
+
+ private final static BigInteger CERTIFICATE = BigInteger.valueOf(0);
+ private final static BigInteger PRIVATE_KEY = BigInteger.valueOf(1);
+ private final static BigInteger SECRET_KEY = BigInteger.valueOf(2);
+ private final static BigInteger PROTECTED_PRIVATE_KEY = BigInteger.valueOf(3);
+ private final static BigInteger PROTECTED_SECRET_KEY = BigInteger.valueOf(4);
+
+ private final BouncyCastleProvider provider;
+ private final Map<String, ObjectData> entries = new HashMap<String, ObjectData>();
+ private final Map<String, PrivateKey> privateKeyCache = new HashMap<String, PrivateKey>();
+
+ private AlgorithmIdentifier hmacAlgorithm;
+ private KeyDerivationFunc hmacPkbdAlgorithm;
+ private Date creationDate;
+ private Date lastModifiedDate;
+
+ BcFKSKeyStoreSpi(BouncyCastleProvider provider)
+ {
+ this.provider = provider;
+ }
+
+ public Key engineGetKey(String alias, char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ ObjectData ent = (ObjectData)entries.get(alias);
+
+ if (ent != null)
+ {
+ if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY))
+ {
+ PrivateKey cachedKey = (PrivateKey)privateKeyCache.get(alias);
+ if (cachedKey != null)
+ {
+ return cachedKey;
+ }
+
+ EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData());
+ EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.getInstance(encPrivData.getEncryptedPrivateKeyInfo());
+
+ try
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(decryptData("PRIVATE_KEY_ENCRYPTION", encInfo.getEncryptionAlgorithm(), password, encInfo.getEncryptedData()));
+
+ KeyFactory kFact;
+ if (provider != null)
+ {
+ kFact = KeyFactory.getInstance(pInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(), provider);
+ }
+ else
+ {
+ kFact = KeyFactory.getInstance(getPublicKeyAlg(pInfo.getPrivateKeyAlgorithm().getAlgorithm()));
+ }
+
+ PrivateKey privateKey = kFact.generatePrivate(new PKCS8EncodedKeySpec(pInfo.getEncoded()));
+
+ // check that the key pair and the certificate public key are consistent
+ // TODO: new ConsistentKeyPair(engineGetCertificate(alias).getPublicKey(), privateKey);
+
+ privateKeyCache.put(alias, privateKey);
+
+ return privateKey;
+ }
+ catch (Exception e)
+ {
+ throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover private key (" + alias + "): " + e.getMessage());
+ }
+ }
+ else if (ent.getType().equals(SECRET_KEY) || ent.getType().equals(PROTECTED_SECRET_KEY))
+ {
+ EncryptedSecretKeyData encKeyData = EncryptedSecretKeyData.getInstance(ent.getData());
+
+ try
+ {
+ SecretKeyData keyData = SecretKeyData.getInstance(decryptData("SECRET_KEY_ENCRYPTION", encKeyData.getKeyEncryptionAlgorithm(), password, encKeyData.getEncryptedKeyData()));
+ SecretKeyFactory kFact;
+ if (provider != null)
+ {
+ kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId(), provider);
+ }
+ else
+ {
+ kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId());
+ }
+
+ return kFact.generateSecret(new SecretKeySpec(keyData.getKeyBytes(), keyData.getKeyAlgorithm().getId()));
+ }
+ catch (Exception e)
+ {
+ throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): " + e.getMessage());
+ }
+ }
+ else
+ {
+ throw new UnrecoverableKeyException("BCFKS KeyStore unable to recover secret key (" + alias + "): type not recognized");
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(String alias)
+ {
+ ObjectData ent = (ObjectData)entries.get(alias);
+
+ if (ent != null)
+ {
+ if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY))
+ {
+ EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData());
+ org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain();
+ Certificate[] chain = new X509Certificate[certificates.length];
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chain[i] = decodeCertificate(certificates[i]);
+ }
+
+ return chain;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate engineGetCertificate(String s)
+ {
+ ObjectData ent = (ObjectData)entries.get(s);
+
+ if (ent != null)
+ {
+ if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY))
+ {
+ EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData());
+ org.bouncycastle.asn1.x509.Certificate[] certificates = encPrivData.getCertificateChain();
+
+ return decodeCertificate(certificates[0]);
+ }
+ else if (ent.getType().equals(CERTIFICATE))
+ {
+ return decodeCertificate(ent.getData());
+ }
+ }
+
+ return null;
+ }
+
+ private Certificate decodeCertificate(Object cert)
+ {
+ if (provider != null)
+ {
+ try
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", provider);
+
+ return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ try
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ return certFact.generateCertificate(new ByteArrayInputStream(org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ }
+
+ public Date engineGetCreationDate(String s)
+ {
+ ObjectData ent = (ObjectData)entries.get(s);
+
+ if (ent != null)
+ {
+ try
+ {
+ // we return last modified as it represents date current state of entry was created
+ return ent.getLastModifiedDate().getDate();
+ }
+ catch (ParseException e)
+ {
+ return new Date(); // it's here, but...
+ }
+ }
+
+ return null;
+ }
+
+ public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
+ throws KeyStoreException
+ {
+ Date creationDate = new Date();
+ Date lastEditDate = creationDate;
+
+ ObjectData entry = (ObjectData)entries.get(alias);
+ if (entry != null)
+ {
+ creationDate = extractCreationDate(entry, creationDate);
+ }
+
+ privateKeyCache.remove(alias);
+
+ if (key instanceof PrivateKey)
+ {
+ if (chain == null)
+ {
+ throw new KeyStoreException("BCFKS KeyStore requires a certificate chain for private key storage.");
+ }
+
+ try
+ {
+ // check that the key pair and the certificate public are consistent
+ // TODO: new ConsistentKeyPair(chain[0].getPublicKey(), (PrivateKey)key);
+
+ byte[] encodedKey = key.getEncoded();
+
+ KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8);
+ byte[] keyBytes = generateKey(pbkdAlgId, "PRIVATE_KEY_ENCRYPTION", ((password != null) ? password : new char[0]));
+
+ Cipher c;
+ if (provider == null)
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding");
+ }
+ else
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding", provider);
+ }
+
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"));
+
+ byte[] encryptedKey = c.doFinal(encodedKey);
+
+ AlgorithmParameters algParams = c.getParameters();
+
+ PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded())));
+
+ EncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey);
+
+ EncryptedPrivateKeyData keySeq = createPrivateKeySequence(keyInfo, chain);
+
+ entries.put(alias, new ObjectData(PRIVATE_KEY, alias, creationDate, lastEditDate, keySeq.getEncoded(), null));
+ }
+ catch (Exception e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e);
+ }
+ }
+ else if (key instanceof SecretKey)
+ {
+ if (chain != null)
+ {
+ throw new KeyStoreException("BCFKS KeyStore cannot store certificate chain with secret key.");
+ }
+
+ try
+ {
+ byte[] encodedKey = key.getEncoded();
+
+ KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8);
+ byte[] keyBytes = generateKey(pbkdAlgId, "SECRET_KEY_ENCRYPTION", ((password != null) ? password : new char[0]));
+
+ Cipher c;
+ if (provider == null)
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding");
+ }
+ else
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding", provider);
+ }
+
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"));
+
+
+ String keyAlg = Strings.toUpperCase(key.getAlgorithm());
+ byte[] encryptedKey;
+
+ if (keyAlg.indexOf("AES") > -1)
+ {
+ encryptedKey = c.doFinal(new SecretKeyData(NISTObjectIdentifiers.aes, encodedKey).getEncoded());
+ }
+ else
+ {
+ ASN1ObjectIdentifier algOid = (ASN1ObjectIdentifier)oidMap.get(keyAlg);
+ if (algOid != null)
+ {
+ encryptedKey = c.doFinal(new SecretKeyData(algOid, encodedKey).getEncoded());
+ }
+ else
+ {
+ throw new KeyStoreException("BCFKS KeyStore cannot recognize secret key (" + keyAlg + ") for storage.");
+ }
+ }
+
+
+ AlgorithmParameters algParams = c.getParameters();
+
+ PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded())));
+
+ EncryptedSecretKeyData keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey);
+
+ entries.put(alias, new ObjectData(SECRET_KEY, alias, creationDate, lastEditDate, keyData.getEncoded(), null));
+ }
+ catch (Exception e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore exception storing private key: " + e.toString(), e);
+ }
+ }
+ else
+ {
+ throw new KeyStoreException("BCFKS KeyStore unable to recognize key.");
+ }
+
+ lastModifiedDate = lastEditDate;
+ }
+
+ private SecureRandom getDefaultSecureRandom()
+ {
+ return new SecureRandom();
+ }
+
+ private EncryptedPrivateKeyData createPrivateKeySequence(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo, Certificate[] chain)
+ throws CertificateEncodingException
+ {
+ org.bouncycastle.asn1.x509.Certificate[] certChain = new org.bouncycastle.asn1.x509.Certificate[chain.length];
+ for (int i = 0; i != chain.length; i++)
+ {
+ certChain[i] = org.bouncycastle.asn1.x509.Certificate.getInstance(chain[i].getEncoded());
+ }
+
+ return new EncryptedPrivateKeyData(encryptedPrivateKeyInfo, certChain);
+ }
+
+ public void engineSetKeyEntry(String alias, byte[] keyBytes, Certificate[] chain)
+ throws KeyStoreException
+ {
+ Date creationDate = new Date();
+ Date lastEditDate = creationDate;
+
+ ObjectData entry = (ObjectData)entries.get(alias);
+ if (entry != null)
+ {
+ creationDate = extractCreationDate(entry, creationDate);
+ }
+
+ if (chain != null)
+ {
+ EncryptedPrivateKeyInfo encInfo;
+
+ try
+ {
+ encInfo = EncryptedPrivateKeyInfo.getInstance(keyBytes);
+ }
+ catch (Exception e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore private key encoding must be an EncryptedPrivateKeyInfo.", e);
+ }
+
+ try
+ {
+ privateKeyCache.remove(alias);
+ entries.put(alias, new ObjectData(PROTECTED_PRIVATE_KEY, alias, creationDate, lastEditDate, createPrivateKeySequence(encInfo, chain).getEncoded(), null));
+ }
+ catch (Exception e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e);
+ }
+ }
+ else
+ {
+ try
+ {
+ entries.put(alias, new ObjectData(PROTECTED_SECRET_KEY, alias, creationDate, lastEditDate, keyBytes, null));
+ }
+ catch (Exception e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore exception storing protected private key: " + e.toString(), e);
+ }
+ }
+
+ lastModifiedDate = lastEditDate;
+ }
+
+ public void engineSetCertificateEntry(String alias, Certificate certificate)
+ throws KeyStoreException
+ {
+ ObjectData entry = (ObjectData)entries.get(alias);
+ Date creationDate = new Date();
+ Date lastEditDate = creationDate;
+
+ if (entry != null)
+ {
+ if (!entry.getType().equals(CERTIFICATE))
+ {
+ throw new KeyStoreException("BCFKS KeyStore already has a key entry with alias " + alias);
+ }
+
+ creationDate = extractCreationDate(entry, creationDate);
+ }
+
+ try
+ {
+ entries.put(alias, new ObjectData(CERTIFICATE, alias, creationDate, lastEditDate, certificate.getEncoded(), null));
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new ExtKeyStoreException("BCFKS KeyStore unable to handle certificate: " + e.getMessage(), e);
+ }
+
+ lastModifiedDate = lastEditDate;
+ }
+
+ private Date extractCreationDate(ObjectData entry, Date creationDate)
+ {
+ try
+ {
+ creationDate = entry.getCreationDate().getDate();
+ }
+ catch (ParseException e)
+ {
+ // this should never happen, if it does we'll leave creation date unmodified and hope for the best.
+ }
+ return creationDate;
+ }
+
+ public void engineDeleteEntry(String alias)
+ throws KeyStoreException
+ {
+ ObjectData entry = (ObjectData)entries.get(alias);
+
+ if (entry == null)
+ {
+ return;
+ }
+
+ privateKeyCache.remove(alias);
+ entries.remove(alias);
+
+ lastModifiedDate = new Date();
+ }
+
+ public Enumeration<String> engineAliases()
+ {
+ final Iterator<String> it = new HashSet(entries.keySet()).iterator();
+
+ return new Enumeration()
+ {
+ public boolean hasMoreElements()
+ {
+ return it.hasNext();
+ }
+
+ public Object nextElement()
+ {
+ return it.next();
+ }
+ };
+ }
+
+ public boolean engineContainsAlias(String alias)
+ {
+ if (alias == null)
+ {
+ throw new NullPointerException("alias value is null");
+ }
+
+ return entries.containsKey(alias);
+ }
+
+ public int engineSize()
+ {
+ return entries.size();
+ }
+
+ public boolean engineIsKeyEntry(String alias)
+ {
+ ObjectData ent = (ObjectData)entries.get(alias);
+
+ if (ent != null)
+ {
+ BigInteger entryType = ent.getType();
+ return entryType.equals(PRIVATE_KEY) || entryType.equals(SECRET_KEY)
+ || entryType.equals(PROTECTED_PRIVATE_KEY) || entryType.equals(PROTECTED_SECRET_KEY);
+ }
+
+ return false;
+ }
+
+ public boolean engineIsCertificateEntry(String alias)
+ {
+ ObjectData ent = (ObjectData)entries.get(alias);
+
+ if (ent != null)
+ {
+ return ent.getType().equals(CERTIFICATE);
+ }
+
+ return false;
+ }
+
+ public String engineGetCertificateAlias(Certificate certificate)
+ {
+ if (certificate == null)
+ {
+ return null;
+ }
+
+ byte[] encodedCert;
+ try
+ {
+ encodedCert = certificate.getEncoded();
+ }
+ catch (CertificateEncodingException e)
+ {
+ return null;
+ }
+
+ for (Iterator<String> it = entries.keySet().iterator(); it.hasNext(); )
+ {
+ String alias = (String)it.next();
+ ObjectData ent = (ObjectData)entries.get(alias);
+
+ if (ent.getType().equals(CERTIFICATE))
+ {
+ if (Arrays.areEqual(ent.getData(), encodedCert))
+ {
+ return alias;
+ }
+ }
+ else if (ent.getType().equals(PRIVATE_KEY) || ent.getType().equals(PROTECTED_PRIVATE_KEY))
+ {
+ try
+ {
+ EncryptedPrivateKeyData encPrivData = EncryptedPrivateKeyData.getInstance(ent.getData());
+ if (Arrays.areEqual(encPrivData.getCertificateChain()[0].toASN1Primitive().getEncoded(), encodedCert))
+ {
+ return alias;
+ }
+ }
+ catch (IOException e)
+ {
+ // ignore - this should never happen
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] generateKey(KeyDerivationFunc pbkdAlgorithm, String purpose, char[] password)
+ throws IOException
+ {
+ byte[] encPassword = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+ byte[] differentiator = PBEParametersGenerator.PKCS12PasswordToBytes(purpose.toCharArray());
+
+ int keySizeInBytes;
+ PKCS5S2ParametersGenerator pGen = new PKCS5S2ParametersGenerator(new SHA512Digest());
+
+ if (pbkdAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2))
+ {
+ PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(pbkdAlgorithm.getParameters());
+
+ if (pbkdf2Params.getPrf().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512))
+ {
+
+ pGen.init(Arrays.concatenate(encPassword, differentiator), pbkdf2Params.getSalt(), pbkdf2Params.getIterationCount().intValue());
+
+ keySizeInBytes = pbkdf2Params.getKeyLength().intValue();
+ }
+ else
+ {
+ throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD PRF.");
+ }
+ }
+ else
+ {
+ throw new IOException("BCFKS KeyStore: unrecognized MAC PBKD.");
+ }
+
+ return ((KeyParameter)pGen.generateDerivedParameters(keySizeInBytes * 8)).getKey();
+ }
+
+ private void verifyMac(byte[] content, PbkdMacIntegrityCheck integrityCheck, char[] password)
+ throws NoSuchAlgorithmException, IOException
+ {
+ byte[] check = calculateMac(content, integrityCheck.getMacAlgorithm(), integrityCheck.getPbkdAlgorithm(), password);
+
+ if (!Arrays.constantTimeAreEqual(check, integrityCheck.getMac()))
+ {
+ throw new IOException("BCFKS KeyStore corrupted: MAC calculation failed.");
+ }
+ }
+
+ private byte[] calculateMac(byte[] content, AlgorithmIdentifier algorithm, KeyDerivationFunc pbkdAlgorithm, char[] password)
+ throws NoSuchAlgorithmException, IOException
+ {
+ String algorithmId = algorithm.getAlgorithm().getId();
+
+ Mac mac;
+ if (provider != null)
+ {
+ mac = Mac.getInstance(algorithmId, provider);
+ }
+ else
+ {
+ mac = Mac.getInstance(algorithmId);
+ }
+
+ try
+ {
+ mac.init(new SecretKeySpec(generateKey(pbkdAlgorithm, "INTEGRITY_CHECK", ((password != null) ? password : new char[0])), algorithmId));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new IOException("Cannot set up MAC calculation: " + e.getMessage());
+ }
+
+ return mac.doFinal(content);
+ }
+
+ public void engineStore(OutputStream outputStream, char[] password)
+ throws IOException, NoSuchAlgorithmException, CertificateException
+ {
+ ObjectData[] dataArray = (ObjectData[])entries.values().toArray(new ObjectData[entries.size()]);
+
+ KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(256 / 8);
+ byte[] keyBytes = generateKey(pbkdAlgId, "STORE_ENCRYPTION", ((password != null) ? password : new char[0]));
+
+ ObjectStoreData storeData = new ObjectStoreData(hmacAlgorithm, creationDate, lastModifiedDate, new ObjectDataSequence(dataArray), null);
+ EncryptedObjectStoreData encStoreData;
+
+ try
+ {
+ Cipher c;
+ if (provider == null)
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding");
+ }
+ else
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding", provider);
+ }
+
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"));
+
+ byte[] encOut = c.doFinal(storeData.getEncoded());
+
+ AlgorithmParameters algorithmParameters = c.getParameters();
+
+ PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algorithmParameters.getEncoded())));
+
+ encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new NoSuchAlgorithmException(e.toString());
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IOException(e.toString());
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new IOException(e.toString());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new IOException(e.toString());
+ }
+
+ // update the salt
+ PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(hmacPkbdAlgorithm.getParameters());
+
+ byte[] pbkdSalt = new byte[pbkdf2Params.getSalt().length];
+ getDefaultSecureRandom().nextBytes(pbkdSalt);
+
+ hmacPkbdAlgorithm = new KeyDerivationFunc(hmacPkbdAlgorithm.getAlgorithm(), new PBKDF2Params(pbkdSalt, pbkdf2Params.getIterationCount().intValue(), pbkdf2Params.getKeyLength().intValue(), pbkdf2Params.getPrf()));
+
+ byte[] mac = calculateMac(encStoreData.getEncoded(), hmacAlgorithm, hmacPkbdAlgorithm, password);
+
+ ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(new PbkdMacIntegrityCheck(hmacAlgorithm, hmacPkbdAlgorithm, mac)));
+
+ outputStream.write(store.getEncoded());
+
+ outputStream.flush();
+ }
+
+ public void engineLoad(InputStream inputStream, char[] password)
+ throws IOException, NoSuchAlgorithmException, CertificateException
+ {
+ // reset any current values
+ entries.clear();
+ privateKeyCache.clear();
+
+ lastModifiedDate = creationDate = null;
+ hmacAlgorithm = null;
+
+ if (inputStream == null)
+ {
+ // initialise defaults
+ lastModifiedDate = creationDate = new Date();
+
+ hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE);
+ hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(512 / 8);
+
+ return;
+ }
+
+ ASN1InputStream aIn = new ASN1InputStream(inputStream);
+
+ ObjectStore store = ObjectStore.getInstance(aIn.readObject());
+
+ ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck();
+ if (integrityCheck.getType() == ObjectStoreIntegrityCheck.PBKD_MAC_CHECK)
+ {
+ PbkdMacIntegrityCheck pbkdMacIntegrityCheck = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck());
+
+ hmacAlgorithm = pbkdMacIntegrityCheck.getMacAlgorithm();
+ hmacPkbdAlgorithm = pbkdMacIntegrityCheck.getPbkdAlgorithm();
+
+ verifyMac(store.getStoreData().toASN1Primitive().getEncoded(), pbkdMacIntegrityCheck, password);
+ }
+ else
+ {
+ throw new IOException("BCFKS KeyStore unable to recognize integrity check.");
+ }
+
+ ASN1Encodable sData = store.getStoreData();
+
+ ObjectStoreData storeData;
+ if (sData instanceof EncryptedObjectStoreData)
+ {
+ EncryptedObjectStoreData encryptedStoreData = (EncryptedObjectStoreData)sData;
+ AlgorithmIdentifier protectAlgId = encryptedStoreData.getEncryptionAlgorithm();
+
+ storeData = ObjectStoreData.getInstance(decryptData("STORE_ENCRYPTION", protectAlgId, password, encryptedStoreData.getEncryptedContent().getOctets()));
+ }
+ else
+ {
+ storeData = ObjectStoreData.getInstance(sData);
+ }
+
+ try
+ {
+ creationDate = storeData.getCreationDate().getDate();
+ lastModifiedDate = storeData.getLastModifiedDate().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IOException("BCFKS KeyStore unable to parse store data information.");
+ }
+
+ if (!storeData.getIntegrityAlgorithm().equals(hmacAlgorithm))
+ {
+ throw new IOException("BCFKS KeyStore storeData integrity algorithm does not match store integrity algorithm.");
+ }
+
+ for (Iterator it = storeData.getObjectDataSequence().iterator(); it.hasNext(); )
+ {
+ ObjectData objData = ObjectData.getInstance(it.next());
+
+ entries.put(objData.getIdentifier(), objData);
+ }
+ }
+
+ private byte[] decryptData(String purpose, AlgorithmIdentifier protectAlgId, char[] password, byte[] encryptedData)
+ throws IOException
+ {
+ if (!protectAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ throw new IOException("BCFKS KeyStore cannot recognize protection algorithm.");
+ }
+
+ PBES2Parameters pbes2Parameters = PBES2Parameters.getInstance(protectAlgId.getParameters());
+ EncryptionScheme algId = pbes2Parameters.getEncryptionScheme();
+
+ if (!algId.getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_CCM))
+ {
+ throw new IOException("BCFKS KeyStore cannot recognize protection encryption algorithm.");
+ }
+
+ try
+ {
+ CCMParameters ccmParameters = CCMParameters.getInstance(algId.getParameters());
+ Cipher c;
+ AlgorithmParameters algParams;
+ if (provider == null)
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding");
+ algParams = AlgorithmParameters.getInstance("CCM");
+ }
+ else
+ {
+ c = Cipher.getInstance("AES/CCM/NoPadding", provider);
+ algParams = AlgorithmParameters.getInstance("CCM", provider);
+ }
+
+ algParams.init(ccmParameters.getEncoded());
+
+ byte[] keyBytes = generateKey(pbes2Parameters.getKeyDerivationFunc(), purpose, ((password != null) ? password : new char[0]));
+
+ c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), algParams);
+
+ byte[] rv = c.doFinal(encryptedData);
+ return rv;
+ }
+ catch (Exception e)
+ {
+ throw new IOException(e.toString());
+ }
+ }
+
+ private KeyDerivationFunc generatePkbdAlgorithmIdentifier(int keySizeInBytes)
+ {
+ byte[] pbkdSalt = new byte[512 / 8];
+ getDefaultSecureRandom().nextBytes(pbkdSalt);
+ return new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(pbkdSalt, 1024, keySizeInBytes, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE)));
+ }
+
+ public static class Std
+ extends BcFKSKeyStoreSpi
+ {
+ public Std()
+ {
+ super(new BouncyCastleProvider());
+ }
+ }
+
+ public static class Def
+ extends BcFKSKeyStoreSpi
+ {
+ public Def()
+ {
+ super(null);
+ }
+ }
+
+ private static class ExtKeyStoreException
+ extends KeyStoreException
+ {
+ private final Throwable cause;
+
+ ExtKeyStoreException(String msg, Throwable cause)
+ {
+ super(msg);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index 123b7eb0..c112f418 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -88,7 +88,7 @@ import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.PKCS12Key;
import org.bouncycastle.jcajce.PKCS12StoreParameter;
import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
@@ -226,7 +226,7 @@ public class PKCS12KeyStoreSpi
private static byte[] getDigest(SubjectPublicKeyInfo spki)
{
- Digest digest = new SHA1Digest();
+ Digest digest = DigestFactory.createSHA1();
byte[] resBuf = new byte[digest.getDigestSize()];
byte[] bytes = spki.getPublicKeyData().getBytes();
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
index 58f10701..1c131468 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -16,7 +16,11 @@ import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.AESWrapEngine;
import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
import org.bouncycastle.crypto.engines.RFC5649WrapEngine;
@@ -34,10 +38,12 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
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.BaseSecretKeyFactory;
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.spec.AEADParameterSpec;
public final class AES
{
@@ -56,7 +62,7 @@ public final class AES
{
public BlockCipher get()
{
- return new AESFastEngine();
+ return new AESEngine();
}
});
}
@@ -67,7 +73,7 @@ public final class AES
{
public CBC()
{
- super(new CBCBlockCipher(new AESFastEngine()), 128);
+ super(new CBCBlockCipher(new AESEngine()), 128);
}
}
@@ -76,7 +82,7 @@ public final class AES
{
public CFB()
{
- super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
+ super(new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)), 128);
}
}
@@ -85,7 +91,7 @@ public final class AES
{
public OFB()
{
- super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
+ super(new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)), 128);
}
}
@@ -94,7 +100,7 @@ public final class AES
{
public GCM()
{
- super(new GCMBlockCipher(new AESFastEngine()));
+ super(new GCMBlockCipher(new AESEngine()));
}
}
@@ -103,7 +109,7 @@ public final class AES
{
public CCM()
{
- super(new CCMBlockCipher(new AESFastEngine()), false, 16);
+ super(new CCMBlockCipher(new AESEngine()), false, 16);
}
}
@@ -112,7 +118,7 @@ public final class AES
{
public AESCMAC()
{
- super(new CMac(new AESFastEngine()));
+ super(new CMac(new AESEngine()));
}
}
@@ -121,7 +127,81 @@ public final class AES
{
public AESGMAC()
{
- super(new GMac(new GCMBlockCipher(new AESFastEngine())));
+ super(new GMac(new GCMBlockCipher(new AESEngine())));
+ }
+ }
+
+ public static class AESCCMMAC
+ extends BaseMac
+ {
+ public AESCCMMAC()
+ {
+ super(new CCMMac());
+ }
+
+ private static class CCMMac
+ implements Mac
+ {
+ private final CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine());
+
+ private int macLength = 8;
+
+ public void init(CipherParameters params)
+ throws IllegalArgumentException
+ {
+ ccm.init(true, params);
+
+ this.macLength = ccm.getMac().length;
+ }
+
+ public String getAlgorithmName()
+ {
+ return ccm.getAlgorithmName() + "Mac";
+ }
+
+ public int getMacSize()
+ {
+ return macLength;
+ }
+
+ public void update(byte in)
+ throws IllegalStateException
+ {
+ ccm.processAADByte(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ throws DataLengthException, IllegalStateException
+ {
+ ccm.processAADBytes(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ try
+ {
+ return ccm.doFinal(out, 0);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new IllegalStateException("exception on doFinal(): " + e.toString());
+ }
+ }
+
+ public void reset()
+ {
+ ccm.reset();
+ }
+ }
+ }
+
+ static public class KeyFactory
+ extends BaseSecretKeyFactory
+ {
+ public KeyFactory()
+ {
+ super("AES", null);
}
}
@@ -130,7 +210,7 @@ public final class AES
{
public Poly1305()
{
- super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine()));
+ super(new org.bouncycastle.crypto.macs.Poly1305(new AESEngine()));
}
}
@@ -157,7 +237,7 @@ public final class AES
{
public RFC3211Wrap()
{
- super(new RFC3211WrapEngine(new AESFastEngine()), 16);
+ super(new RFC3211WrapEngine(new AESEngine()), 16);
}
}
@@ -166,7 +246,7 @@ public final class AES
{
public RFC5649Wrap()
{
- super(new RFC5649WrapEngine(new AESFastEngine()));
+ super(new RFC5649WrapEngine(new AESEngine()));
}
}
@@ -178,7 +258,7 @@ public final class AES
{
public PBEWithAESCBC()
{
- super(new CBCBlockCipher(new AESFastEngine()));
+ super(new CBCBlockCipher(new AESEngine()));
}
}
@@ -190,7 +270,7 @@ public final class AES
{
public PBEWithSHA1AESCBC128()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 128, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 128, 16);
}
}
@@ -199,7 +279,7 @@ public final class AES
{
public PBEWithSHA1AESCBC192()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 192, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 192, 16);
}
}
@@ -208,7 +288,7 @@ public final class AES
{
public PBEWithSHA1AESCBC256()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 256, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 256, 16);
}
}
@@ -220,7 +300,7 @@ public final class AES
{
public PBEWithSHA256AESCBC128()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 128, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 128, 16);
}
}
@@ -229,7 +309,7 @@ public final class AES
{
public PBEWithSHA256AESCBC192()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 192, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 192, 16);
}
}
@@ -238,7 +318,7 @@ public final class AES
{
public PBEWithSHA256AESCBC256()
{
- super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 256, 16);
+ super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 256, 16);
}
}
@@ -437,6 +517,7 @@ public final class AES
SecureRandom random)
throws InvalidAlgorithmParameterException
{
+ // TODO: add support for GCMParameterSpec as a template.
throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
}
@@ -475,6 +556,7 @@ public final class AES
SecureRandom random)
throws InvalidAlgorithmParameterException
{
+ // TODO: add support for GCMParameterSpec as a template.
throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
}
@@ -494,7 +576,7 @@ public final class AES
try
{
params = createParametersInstance("GCM");
- params.init(new GCMParameters(nonce, 12).getEncoded());
+ params.init(new GCMParameters(nonce, 16).getEncoded());
}
catch (Exception e)
{
@@ -526,6 +608,10 @@ public final class AES
{
gcmParams = GcmSpecUtil.extractGcmParameters(paramSpec);
}
+ else if (paramSpec instanceof AEADParameterSpec)
+ {
+ gcmParams = new GCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8);
+ }
else
{
throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
@@ -580,7 +666,11 @@ public final class AES
{
return GcmSpecUtil.extractGcmSpec(gcmParams.toASN1Primitive());
}
- return new IvParameterSpec(gcmParams.getNonce());
+ return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8);
+ }
+ if (paramSpec == AEADParameterSpec.class)
+ {
+ return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8);
}
if (paramSpec == IvParameterSpec.class)
{
@@ -603,6 +693,10 @@ public final class AES
{
ccmParams = CCMParameters.getInstance(GcmSpecUtil.extractGcmParameters(paramSpec));
}
+ else if (paramSpec instanceof AEADParameterSpec)
+ {
+ ccmParams = new CCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8);
+ }
else
{
throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
@@ -657,7 +751,11 @@ public final class AES
{
return GcmSpecUtil.extractGcmSpec(ccmParams.toASN1Primitive());
}
- return new IvParameterSpec(ccmParams.getNonce());
+ return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8);
+ }
+ if (paramSpec == AEADParameterSpec.class)
+ {
+ return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8);
}
if (paramSpec == IvParameterSpec.class)
{
@@ -787,7 +885,12 @@ public final class AES
provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CCM, PREFIX + "$KeyGen256");
provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
-
+
+ provider.addAlgorithm("Mac.AESCCMMAC", PREFIX + "$AESCCMMAC");
+ provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes128_CCM.getId(), "AESCCMMAC");
+ provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes192_CCM.getId(), "AESCCMMAC");
+ provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes256_CCM.getId(), "AESCCMMAC");
+
provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC");
provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC");
provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC");
@@ -830,7 +933,10 @@ public final class AES
provider.addAlgorithm("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
provider.addAlgorithm("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
provider.addAlgorithm("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
-
+
+ provider.addAlgorithm("SecretKeyFactory.AES", PREFIX + "$KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory", NISTObjectIdentifiers.aes, PREFIX + "$KeyFactory");
+
provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And128BitAESCBCOpenSSL");
provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And192BitAESCBCOpenSSL");
provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And256BitAESCBCOpenSSL");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java
index ff748ae4..af71b4ee 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java
@@ -1,6 +1,7 @@
package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.ChaCha7539Engine;
import org.bouncycastle.crypto.engines.ChaChaEngine;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
@@ -31,6 +32,24 @@ public final class ChaCha
}
}
+ public static class Base7539
+ extends BaseStreamCipher
+ {
+ public Base7539()
+ {
+ super(new ChaCha7539Engine(), 12);
+ }
+ }
+
+ public static class KeyGen7539
+ extends BaseKeyGenerator
+ {
+ public KeyGen7539()
+ {
+ super("ChaCha7539", 256, new CipherKeyGenerator());
+ }
+ }
+
public static class Mappings
extends AlgorithmProvider
{
@@ -46,6 +65,8 @@ public final class ChaCha
provider.addAlgorithm("Cipher.CHACHA", PREFIX + "$Base");
provider.addAlgorithm("KeyGenerator.CHACHA", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Cipher.CHACHA7539", PREFIX + "$Base7539");
+ provider.addAlgorithm("KeyGenerator.CHACHA7539", PREFIX + "$KeyGen7539");
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
index e68e59c4..ab7718c2 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -12,6 +12,7 @@ import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.engines.DESedeEngine;
@@ -398,6 +399,8 @@ public final class DESede
provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory", OIWObjectIdentifiers.desEDE, PREFIX + "$KeyFactory");
+
provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
index edce1180..7f41877d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -119,12 +119,19 @@ public class PBEPBKDF2
extends BaseSecretKeyFactory
{
private int scheme;
+ private int defaultDigest;
public BasePBKDF2(String name, int scheme)
{
+ this(name, scheme, SHA1);
+ }
+
+ public BasePBKDF2(String name, int scheme, int defaultDigest)
+ {
super(name, PKCSObjectIdentifiers.id_PBKDF2);
this.scheme = scheme;
+ this.defaultDigest = defaultDigest;
}
protected SecretKey engineGenerateSecret(
@@ -170,7 +177,7 @@ public class PBEPBKDF2
}
else
{
- int digest = SHA1;
+ int digest = defaultDigest;
int keySize = pbeSpec.getKeyLength();
int ivSize = -1; // JDK 1,2 and earlier does not understand simplified version.
CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
@@ -194,6 +201,22 @@ public class PBEPBKDF2
{
return SHA1;
}
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA256))
+ {
+ return SHA256;
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA224))
+ {
+ return SHA224;
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA384))
+ {
+ return SHA384;
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA512))
+ {
+ return SHA512;
+ }
throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm);
}
@@ -208,6 +231,41 @@ public class PBEPBKDF2
}
}
+ public static class PBKDF2withSHA224
+ extends BasePBKDF2
+ {
+ public PBKDF2withSHA224()
+ {
+ super("PBKDF2", PKCS5S2_UTF8, SHA224);
+ }
+ }
+
+ public static class PBKDF2withSHA256
+ extends BasePBKDF2
+ {
+ public PBKDF2withSHA256()
+ {
+ super("PBKDF2", PKCS5S2_UTF8, SHA256);
+ }
+ }
+
+ public static class PBKDF2withSHA384
+ extends BasePBKDF2
+ {
+ public PBKDF2withSHA384()
+ {
+ super("PBKDF2", PKCS5S2_UTF8, SHA384);
+ }
+ }
+ public static class PBKDF2withSHA512
+ extends BasePBKDF2
+ {
+ public PBKDF2withSHA512()
+ {
+ super("PBKDF2", PKCS5S2_UTF8, SHA512);
+ }
+ }
+
public static class PBKDF2with8BIT
extends BasePBKDF2
{
@@ -231,9 +289,16 @@ public class PBEPBKDF2
provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "$AlgParams");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
provider.addAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1", "PBKDF2");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1ANDUTF8", "PBKDF2");
provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHASCII", PREFIX + "$PBKDF2with8BIT");
provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITH8BIT", "PBKDF2WITHASCII");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1AND8BIT", "PBKDF2WITHASCII");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA224", PREFIX + "$PBKDF2withSHA224");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512");
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java
new file mode 100644
index 00000000..735e5bd5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Poly1305.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+public class Poly1305
+{
+ private Poly1305()
+ {
+ }
+
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new org.bouncycastle.crypto.macs.Poly1305());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Poly1305", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Poly1305.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Mac.POLY1305", PREFIX + "$Mac");
+
+ provider.addAlgorithm("KeyGenerator.POLY1305", PREFIX + "$KeyGen");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
index ef983fff..42058e51 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
@@ -345,7 +345,7 @@ public final class RC2
Class paramSpec)
throws InvalidParameterSpecException
{
- if (paramSpec == RC2ParameterSpec.class)
+ if (paramSpec == RC2ParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
{
if (parameterVersion != -1)
{
@@ -360,7 +360,7 @@ public final class RC2
}
}
- if (paramSpec == IvParameterSpec.class)
+ if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
{
return new IvParameterSpec(iv);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java
new file mode 100644
index 00000000..eee822af
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/TLSKDF.java
@@ -0,0 +1,207 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.Mac;
+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.params.KeyParameter;
+import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jcajce.spec.TLSKeyMaterialSpec;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+public class TLSKDF
+{
+ public static class TLSKeyMaterialFactory
+ extends BaseSecretKeyFactory
+ {
+ protected TLSKeyMaterialFactory(String algName)
+ {
+ super(algName, null);
+ }
+ }
+
+ public static final class TLS10
+ extends TLSKeyMaterialFactory
+ {
+ public TLS10()
+ {
+ super("TLS10KDF");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof TLSKeyMaterialSpec)
+ {
+ return new SecretKeySpec(PRF_legacy((TLSKeyMaterialSpec)keySpec), algName);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ public static final class TLS11
+ extends TLSKeyMaterialFactory
+ {
+ public TLS11()
+ {
+ super("TLS11KDF");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof TLSKeyMaterialSpec)
+ {
+ return new SecretKeySpec(PRF_legacy((TLSKeyMaterialSpec)keySpec), algName);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ private static byte[] PRF_legacy(TLSKeyMaterialSpec parameters)
+ {
+ Mac md5Hmac = new HMac(DigestFactory.createMD5());
+ Mac sha1HMac = new HMac(DigestFactory.createSHA1());
+
+ byte[] label = Strings.toByteArray(parameters.getLabel());
+ byte[] labelSeed = Arrays.concatenate(label, parameters.getSeed());
+ byte[] secret = parameters.getSecret();
+
+ int s_half = (secret.length + 1) / 2;
+ byte[] s1 = new byte[s_half];
+ byte[] s2 = new byte[s_half];
+ System.arraycopy(secret, 0, s1, 0, s_half);
+ System.arraycopy(secret, secret.length - s_half, s2, 0, s_half);
+
+ int size = parameters.getLength();
+ byte[] b1 = new byte[size];
+ byte[] b2 = new byte[size];
+
+ hmac_hash(md5Hmac, s1, labelSeed, b1);
+ hmac_hash(sha1HMac, s2, labelSeed, b2);
+
+ for (int i = 0; i < size; i++)
+ {
+ b1[i] ^= b2[i];
+ }
+ return b1;
+ }
+
+ public static class TLS12
+ extends TLSKeyMaterialFactory
+ {
+ private final Mac prf;
+
+ protected TLS12(String algName, Mac prf)
+ {
+ super(algName);
+ this.prf = prf;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof TLSKeyMaterialSpec)
+ {
+ return new SecretKeySpec(PRF((TLSKeyMaterialSpec)keySpec, prf), algName);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ private byte[] PRF(TLSKeyMaterialSpec parameters, Mac prf)
+ {
+ byte[] label = Strings.toByteArray(parameters.getLabel());
+ byte[] labelSeed = Arrays.concatenate(label, parameters.getSeed());
+ byte[] secret = parameters.getSecret();
+
+ byte[] buf = new byte[parameters.getLength()];
+
+ hmac_hash(prf, secret, labelSeed, buf);
+
+ return buf;
+ }
+ }
+
+ public static final class TLS12withSHA256
+ extends TLS12
+ {
+ public TLS12withSHA256()
+ {
+ super("TLS12withSHA256KDF", new HMac(new SHA256Digest()));
+ }
+ }
+
+ public static final class TLS12withSHA384
+ extends TLS12
+ {
+ public TLS12withSHA384()
+ {
+ super("TLS12withSHA384KDF", new HMac(new SHA384Digest()));
+ }
+ }
+
+ public static final class TLS12withSHA512
+ extends TLS12
+ {
+ public TLS12withSHA512()
+ {
+ super("TLS12withSHA512KDF", new HMac(new SHA512Digest()));
+ }
+ }
+
+ private static void hmac_hash(Mac mac, byte[] secret, byte[] seed, byte[] out)
+ {
+ mac.init(new KeyParameter(secret));
+ byte[] a = seed;
+ int size = mac.getMacSize();
+ int iterations = (out.length + size - 1) / size;
+ byte[] buf = new byte[mac.getMacSize()];
+ byte[] buf2 = new byte[mac.getMacSize()];
+ for (int i = 0; i < iterations; i++)
+ {
+ mac.update(a, 0, a.length);
+ mac.doFinal(buf, 0);
+ a = buf;
+ mac.update(a, 0, a.length);
+ mac.update(seed, 0, seed.length);
+ mac.doFinal(buf2, 0);
+ System.arraycopy(buf2, 0, out, (size * i), Math.min(size, out.length - (size * i)));
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = TLSKDF.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("SecretKeyFactory.TLS10KDF", PREFIX + "$TLS10");
+ provider.addAlgorithm("SecretKeyFactory.TLS11KDF", PREFIX + "$TLS11");
+ provider.addAlgorithm("SecretKeyFactory.TLS12WITHSHA256KDF", PREFIX + "$TLS12withSHA256");
+ provider.addAlgorithm("SecretKeyFactory.TLS12WITHSHA384KDF", PREFIX + "$TLS12withSHA384");
+ provider.addAlgorithm("SecretKeyFactory.TLS12WITHSHA512KDF", PREFIX + "$TLS12withSHA512");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
index aa0f22d9..6bd1ba97 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -63,6 +63,7 @@ import org.bouncycastle.jcajce.PBKDF1Key;
import org.bouncycastle.jcajce.PBKDF1KeyWithParameters;
import org.bouncycastle.jcajce.PKCS12Key;
import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
+import org.bouncycastle.jcajce.spec.AEADParameterSpec;
import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
import org.bouncycastle.util.Strings;
@@ -156,9 +157,9 @@ public class BaseBlockCipher
protected BaseBlockCipher(
AEADBlockCipher engine)
{
- baseEngine = engine.getUnderlyingCipher();
- ivLength = baseEngine.getBlockSize();
- cipher = new AEADGenericBlockCipher(engine);
+ this.baseEngine = engine.getUnderlyingCipher();
+ this.ivLength = baseEngine.getBlockSize();
+ this.cipher = new AEADGenericBlockCipher(engine);
}
protected BaseBlockCipher(
@@ -235,6 +236,18 @@ public class BaseBlockCipher
return null;
}
}
+ else if (aeadParams != null)
+ {
+ try
+ {
+ engineParams = createParametersInstance("GCM");
+ engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
else if (ivParam != null)
{
String name = cipher.getUnderlyingCipher().getAlgorithmName();
@@ -254,18 +267,6 @@ public class BaseBlockCipher
throw new RuntimeException(e.toString());
}
}
- else if (aeadParams != null)
- {
- try
- {
- engineParams = createParametersInstance("GCM");
- engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded());
- }
- catch (Exception e)
- {
- throw new RuntimeException(e.toString());
- }
- }
}
return engineParams;
@@ -480,7 +481,7 @@ public class BaseBlockCipher
//
if (!(key instanceof SecretKey))
{
- throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ throw new InvalidKeyException("Key for algorithm " + ((key != null) ? key.getAlgorithm() : null) + " not suitable for symmetric enryption.");
}
//
@@ -513,23 +514,36 @@ public class BaseBlockCipher
if (k instanceof PBEKey && pbeSpec == null)
{
- pbeSpec = new PBEParameterSpec(((PBEKey)k).getSalt(), ((PBEKey)k).getIterationCount());
+ PBEKey pbeKey = (PBEKey)k;
+ if (pbeKey.getSalt() == null)
+ {
+ throw new InvalidAlgorithmParameterException("PBEKey requires parameters to specify salt");
+ }
+ pbeSpec = new PBEParameterSpec(pbeKey.getSalt(), pbeKey.getIterationCount());
}
if (pbeSpec == null && !(k instanceof PBEKey))
{
throw new InvalidKeyException("Algorithm requires a PBE key");
}
+
if (key instanceof BCPBEKey)
{
- if (((BCPBEKey)key).getParam() != null)
+ // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to reject it. If the
+ // key has no parameters it means it's an old-school JCE PBE Key - we use getEncoded() on it.
+ CipherParameters pbeKeyParam = ((BCPBEKey)key).getParam();
+ if (pbeKeyParam instanceof ParametersWithIV)
{
- param = ((BCPBEKey)key).getParam();
+ param = pbeKeyParam;
}
- else
+ else if (pbeKeyParam == null)
{
param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
}
+ else
+ {
+ throw new InvalidKeyException("Algorithm requires a PBE key suitable for PKCS12");
+ }
}
else
{
@@ -619,7 +633,27 @@ public class BaseBlockCipher
param = null;
}
- if (params instanceof IvParameterSpec)
+ if (params instanceof AEADParameterSpec)
+ {
+ if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+ {
+ throw new InvalidAlgorithmParameterException("AEADParameterSpec can only be used with AEAD modes.");
+ }
+
+ AEADParameterSpec aeadSpec = (AEADParameterSpec)params;
+
+ KeyParameter keyParam;
+ if (param instanceof ParametersWithIV)
+ {
+ keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ keyParam = (KeyParameter)param;
+ }
+ param = aeadParams = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData());
+ }
+ else if (params instanceof IvParameterSpec)
{
if (ivLength != 0)
{
@@ -782,6 +816,8 @@ public class BaseBlockCipher
}
}
+
+
if (random != null && padded)
{
param = new ParametersWithRandom(param, random);
@@ -802,16 +838,17 @@ public class BaseBlockCipher
default:
throw new InvalidParameterException("unknown opmode " + opmode + " passed");
}
+
+ if (cipher instanceof AEADGenericBlockCipher && aeadParams == null)
+ {
+ AEADBlockCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher;
+
+ aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV());
+ }
}
catch (final Exception e)
{
- throw new InvalidKeyException(e.getMessage())
- {
- public Throwable getCause()
- {
- return e;
- }
- };
+ throw new InvalidKeyOrParametersException(e.getMessage(), e);
}
}
@@ -1291,4 +1328,21 @@ public class BaseBlockCipher
}
}
}
+
+ private static class InvalidKeyOrParametersException
+ extends InvalidKeyException
+ {
+ private final Throwable cause;
+
+ InvalidKeyOrParametersException(String msg, Throwable cause)
+ {
+ super(msg);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
index 5ceac047..daa53d78 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -1,5 +1,6 @@
package org.bouncycastle.jcajce.provider.symmetric.util;
+import java.lang.reflect.Method;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -13,18 +14,24 @@ import javax.crypto.SecretKey;
import javax.crypto.interfaces.PBEKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.RC2Parameters;
import org.bouncycastle.crypto.params.SkeinParameters;
import org.bouncycastle.jcajce.PKCS12Key;
+import org.bouncycastle.jcajce.spec.AEADParameterSpec;
import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
public class BaseMac
extends MacSpi implements PBE
{
+ private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
private Mac macEngine;
private int scheme = PKCS12;
@@ -121,24 +128,74 @@ public class BaseMac
throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
}
}
+ else
+ {
+ if (params instanceof PBEParameterSpec)
+ {
+ throw new InvalidAlgorithmParameterException("inappropriate parameter type: " + params.getClass().getName());
+ }
+ param = new KeyParameter(key.getEncoded());
+ }
+
+ KeyParameter keyParam;
+ if (param instanceof ParametersWithIV)
+ {
+ keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ keyParam = (KeyParameter)param;
+ }
+
+ if (params instanceof AEADParameterSpec)
+ {
+ AEADParameterSpec aeadSpec = (AEADParameterSpec)params;
+
+ param = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData());
+ }
else if (params instanceof IvParameterSpec)
{
- param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ param = new ParametersWithIV(keyParam, ((IvParameterSpec)params).getIV());
+ }
+ else if (params instanceof RC2ParameterSpec)
+ {
+ param = new ParametersWithIV(new RC2Parameters(keyParam.getKey(), ((RC2ParameterSpec)params).getEffectiveKeyBits()), ((RC2ParameterSpec)params).getIV());
}
else if (params instanceof SkeinParameterSpec)
{
- param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build();
+ param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(keyParam.getKey()).build();
}
else if (params == null)
{
param = new KeyParameter(key.getEncoded());
}
- else
+ else if (gcmSpecClass != null && gcmSpecClass.isAssignableFrom(params.getClass()))
{
- throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ try
+ {
+ Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+ Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+ param = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+ }
+ }
+ else if (!(params instanceof PBEParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName());
}
- macEngine.init(param);
+ try
+ {
+ macEngine.init(param);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot initialize MAC: " + e.getMessage());
+ }
}
protected int engineGetMacLength()
@@ -187,4 +244,18 @@ public class BaseMac
return newTable;
}
+
+ private static Class lookup(String className)
+ {
+ try
+ {
+ Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
+
+ return def;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
index 31896cd2..9e798428 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
@@ -32,7 +32,7 @@ public class BaseSecretKeyFactory
{
if (keySpec instanceof SecretKeySpec)
{
- return (SecretKey)keySpec;
+ return new SecretKeySpec(((SecretKeySpec)keySpec).getEncoded(), algName);
}
throw new InvalidKeySpecException("Invalid KeySpec");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
index 619afa2c..cdf57ac7 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
@@ -98,7 +98,7 @@ public abstract class BaseWrapCipher
protected int engineGetKeySize(
Key key)
{
- return key.getEncoded().length;
+ return key.getEncoded().length * 8;
}
protected int engineGetOutputSize(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
index b5a95526..84da1003 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
@@ -43,7 +43,7 @@ public class IvAlgorithmParameters
Class paramSpec)
throws InvalidParameterSpecException
{
- if (paramSpec == IvParameterSpec.class)
+ if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
{
return new IvParameterSpec(iv);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
index d80d886c..f19df92a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
@@ -11,10 +11,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.GOST3411Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
-import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.TigerDigest;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
@@ -23,6 +20,7 @@ import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.util.DigestFactory;
public interface PBE
{
@@ -36,6 +34,9 @@ public interface PBE
static final int SHA256 = 4;
static final int MD2 = 5;
static final int GOST3411 = 6;
+ static final int SHA224 = 7;
+ static final int SHA384 = 8;
+ static final int SHA512 = 9;
static final int PKCS5S1 = 0;
static final int PKCS5S2 = 1;
@@ -63,10 +64,10 @@ public interface PBE
generator = new PKCS5S1ParametersGenerator(new MD2Digest());
break;
case MD5:
- generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+ generator = new PKCS5S1ParametersGenerator(DigestFactory.createMD5());
break;
case SHA1:
- generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+ generator = new PKCS5S1ParametersGenerator(DigestFactory.createSHA1());
break;
default:
throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
@@ -80,10 +81,10 @@ public interface PBE
generator = new PKCS5S2ParametersGenerator(new MD2Digest());
break;
case MD5:
- generator = new PKCS5S2ParametersGenerator(new MD5Digest());
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createMD5());
break;
case SHA1:
- generator = new PKCS5S2ParametersGenerator(new SHA1Digest());
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA1());
break;
case RIPEMD160:
generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
@@ -92,11 +93,20 @@ public interface PBE
generator = new PKCS5S2ParametersGenerator(new TigerDigest());
break;
case SHA256:
- generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA256());
break;
case GOST3411:
generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
break;
+ case SHA224:
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA224());
+ break;
+ case SHA384:
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA384());
+ break;
+ case SHA512:
+ generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512());
+ break;
default:
throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
}
@@ -109,10 +119,10 @@ public interface PBE
generator = new PKCS12ParametersGenerator(new MD2Digest());
break;
case MD5:
- generator = new PKCS12ParametersGenerator(new MD5Digest());
+ generator = new PKCS12ParametersGenerator(DigestFactory.createMD5());
break;
case SHA1:
- generator = new PKCS12ParametersGenerator(new SHA1Digest());
+ generator = new PKCS12ParametersGenerator(DigestFactory.createSHA1());
break;
case RIPEMD160:
generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
@@ -121,11 +131,20 @@ public interface PBE
generator = new PKCS12ParametersGenerator(new TigerDigest());
break;
case SHA256:
- generator = new PKCS12ParametersGenerator(new SHA256Digest());
+ generator = new PKCS12ParametersGenerator(DigestFactory.createSHA256());
break;
case GOST3411:
generator = new PKCS12ParametersGenerator(new GOST3411Digest());
break;
+ case SHA224:
+ generator = new PKCS12ParametersGenerator(DigestFactory.createSHA224());
+ break;
+ case SHA384:
+ generator = new PKCS12ParametersGenerator(DigestFactory.createSHA384());
+ break;
+ case SHA512:
+ generator = new PKCS12ParametersGenerator(DigestFactory.createSHA512());
+ break;
default:
throw new IllegalStateException("unknown digest scheme for PBE encryption.");
}
@@ -194,11 +213,6 @@ public interface PBE
}
}
- for (int i = 0; i != key.length; i++)
- {
- key[i] = 0;
- }
-
return param;
}
@@ -253,11 +267,6 @@ public interface PBE
}
}
- for (int i = 0; i != key.length; i++)
- {
- key[i] = 0;
- }
-
return param;
}
@@ -283,11 +292,6 @@ public interface PBE
generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
-
- for (int i = 0; i != key.length; i++)
- {
- key[i] = 0;
- }
return param;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java
new file mode 100644
index 00000000..e2a8d63d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/BadBlockException.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import javax.crypto.BadPaddingException;
+
+public class BadBlockException
+ extends BadPaddingException
+{
+ private final Throwable cause;
+
+ public BadBlockException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
index 407a3abb..f5823ac4 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -10,13 +10,6 @@ import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.digests.SHA512tDigest;
import org.bouncycastle.util.Strings;
public class DigestFactory
@@ -29,6 +22,10 @@ public class DigestFactory
private static Set sha512 = new HashSet();
private static Set sha512_224 = new HashSet();
private static Set sha512_256 = new HashSet();
+ private static Set sha3_224 = new HashSet();
+ private static Set sha3_256 = new HashSet();
+ private static Set sha3_384 = new HashSet();
+ private static Set sha3_512 = new HashSet();
private static Map oids = new HashMap();
@@ -65,6 +62,18 @@ public class DigestFactory
sha512_256.add("SHA-512(256)");
sha512_256.add(NISTObjectIdentifiers.id_sha512_256.getId());
+ sha3_224.add("SHA3-224");
+ sha3_224.add(NISTObjectIdentifiers.id_sha3_224.getId());
+
+ sha3_256.add("SHA3-256");
+ sha3_256.add(NISTObjectIdentifiers.id_sha3_256.getId());
+
+ sha3_384.add("SHA3-384");
+ sha3_384.add(NISTObjectIdentifiers.id_sha3_384.getId());
+
+ sha3_512.add("SHA3-512");
+ sha3_512.add(NISTObjectIdentifiers.id_sha3_512.getId());
+
oids.put("MD5", PKCSObjectIdentifiers.md5);
oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
@@ -95,6 +104,18 @@ public class DigestFactory
oids.put("SHA512(256)", NISTObjectIdentifiers.id_sha512_256);
oids.put("SHA-512(256)", NISTObjectIdentifiers.id_sha512_256);
oids.put(NISTObjectIdentifiers.id_sha512_256.getId(), NISTObjectIdentifiers.id_sha512_256);
+
+ oids.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224);
+ oids.put(NISTObjectIdentifiers.id_sha3_224.getId(), NISTObjectIdentifiers.id_sha3_224);
+
+ oids.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256);
+ oids.put(NISTObjectIdentifiers.id_sha3_256.getId(), NISTObjectIdentifiers.id_sha3_256);
+
+ oids.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384);
+ oids.put(NISTObjectIdentifiers.id_sha3_384.getId(), NISTObjectIdentifiers.id_sha3_384);
+
+ oids.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512);
+ oids.put(NISTObjectIdentifiers.id_sha3_512.getId(), NISTObjectIdentifiers.id_sha3_512);
}
public static Digest getDigest(
@@ -104,35 +125,52 @@ public class DigestFactory
if (sha1.contains(digestName))
{
- return new SHA1Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA1();
}
if (md5.contains(digestName))
{
- return new MD5Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createMD5();
}
if (sha224.contains(digestName))
{
- return new SHA224Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA224();
}
if (sha256.contains(digestName))
{
- return new SHA256Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA256();
}
if (sha384.contains(digestName))
{
- return new SHA384Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA384();
}
if (sha512.contains(digestName))
{
- return new SHA512Digest();
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA512();
}
if (sha512_224.contains(digestName))
{
- return new SHA512tDigest(224);
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA512_224();
}
if (sha512_256.contains(digestName))
{
- return new SHA512tDigest(256);
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA512_256();
+ }
+
+ if (sha3_224.contains(digestName))
+ {
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA3_224();
+ }
+ if (sha3_256.contains(digestName))
+ {
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA3_256();
+ }
+ if (sha3_384.contains(digestName))
+ {
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA3_384();
+ }
+ if (sha3_512.contains(digestName))
+ {
+ return org.bouncycastle.crypto.util.DigestFactory.createSHA3_512();
}
return null;
@@ -149,6 +187,10 @@ public class DigestFactory
|| (sha512.contains(digest1) && sha512.contains(digest2))
|| (sha512_224.contains(digest1) && sha512_224.contains(digest2))
|| (sha512_256.contains(digest1) && sha512_256.contains(digest2))
+ || (sha3_224.contains(digest1) && sha3_224.contains(digest2))
+ || (sha3_256.contains(digest1) && sha3_256.contains(digest2))
+ || (sha3_384.contains(digest1) && sha3_384.contains(digest2))
+ || (sha3_512.contains(digest1) && sha3_512.contains(digest2))
|| (md5.contains(digest1) && md5.contains(digest2));
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java
new file mode 100644
index 00000000..b5d9657a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/AEADParameterSpec.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.jcajce.spec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * ParameterSpec for AEAD modes which allows associated data to be added via an algorithm parameter spec.In normal
+ * circumstances you would only want to use this if you had to work with the pre-JDK1.7 Cipher class as associated
+ * data is ignored for the purposes of returning a Cipher's parameters.
+ */
+public class AEADParameterSpec
+ extends IvParameterSpec
+{
+ private final byte[] associatedData;
+ private final int macSizeInBits;
+
+ /**
+ * Base constructor.
+ *
+ * @param nonce nonce/iv to be used
+ * @param macSizeInBits macSize in bits
+ */
+ public AEADParameterSpec(byte[] nonce, int macSizeInBits)
+ {
+ this(nonce, macSizeInBits, null);
+ }
+
+ /**
+ * Base constructor with prepended associated data.
+ *
+ * @param nonce nonce/iv to be used
+ * @param macSizeInBits macSize in bits
+ * @param associatedData associated data to be prepended to the cipher stream.
+ */
+ public AEADParameterSpec(byte[] nonce, int macSizeInBits, byte[] associatedData)
+ {
+ super(nonce);
+
+ this.macSizeInBits = macSizeInBits;
+ this.associatedData = Arrays.clone(associatedData);
+ }
+
+ /**
+ * Return the size of the MAC associated with this parameter spec.
+ *
+ * @return the MAC size in bits.
+ */
+ public int getMacSizeInBits()
+ {
+ return macSizeInBits;
+ }
+
+ /**
+ * Return the associated data associated with this parameter spec.
+ *
+ * @return the associated data, null if there isn't any.
+ */
+ public byte[] getAssociatedData()
+ {
+ return Arrays.clone(associatedData);
+ }
+
+ /**
+ * Return the nonce (same as IV) associated with this parameter spec.
+ *
+ * @return the nonce/IV.
+ */
+ public byte[] getNonce()
+ {
+ return getIV();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
index df0c1454..e053fb93 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
@@ -2,6 +2,8 @@ package org.bouncycastle.jcajce.spec;
import javax.crypto.spec.PBEKeySpec;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
/**
@@ -10,6 +12,8 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
public class PBKDF2KeySpec
extends PBEKeySpec
{
+ private static final AlgorithmIdentifier defaultPRF = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
+
private AlgorithmIdentifier prf;
/**
@@ -28,6 +32,21 @@ public class PBKDF2KeySpec
this.prf = prf;
}
+ /**
+ * Return true if this spec is for the default PRF (HmacSHA1), false otherwise.
+ *
+ * @return true if this spec uses the default PRF, false otherwise.
+ */
+ public boolean isDefaultPrf()
+ {
+ return defaultPRF.equals(prf);
+ }
+
+ /**
+ * Return an AlgorithmIdentifier representing the PRF.
+ *
+ * @return the PRF's AlgorithmIdentifier.
+ */
public AlgorithmIdentifier getPrf()
{
return prf;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/TLSKeyMaterialSpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/TLSKeyMaterialSpec.java
new file mode 100644
index 00000000..6a862c53
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/TLSKeyMaterialSpec.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.jcajce.spec;
+
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Key Spec class for generating TLS key/iv material.
+ */
+public class TLSKeyMaterialSpec
+ implements KeySpec
+{
+ public static final String MASTER_SECRET = "master secret";
+ public static final String KEY_EXPANSION = "key expansion";
+
+ private final byte[] secret;
+ private final String label;
+ private final int length;
+ private final byte[] seed;
+
+ /**
+ * Constructor specifying the basic parameters for a TLS KDF
+ *
+ * @param secret secret to use
+ * @param label e.g. 'master secret', or 'key expansion'
+ * @param length number of bytes of material to be generated
+ * @param seedMaterial array of seed material inputs (to be concatenated together)
+ */
+ public TLSKeyMaterialSpec(byte[] secret, String label, int length, byte[]... seedMaterial)
+ {
+ this.secret = Arrays.clone(secret);
+ this.label = label;
+ this.length = length;
+ this.seed = Arrays.concatenate(seedMaterial);
+ }
+
+ /**
+ * Return the label associated with this spec.
+ *
+ * @return the label to be used with the TLS KDF.
+ */
+ public String getLabel()
+ {
+ return label;
+ }
+
+ /**
+ * Return the number of bytes of key material to be generated for this spec.
+ *
+ * @return the length in bytes of the result.
+ */
+ public int getLength()
+ {
+ return length;
+ }
+
+ /**
+ * Return the secret associated with this spec.
+ *
+ * @return a copy of the secret.
+ */
+ public byte[] getSecret()
+ {
+ return Arrays.clone(secret);
+ }
+
+ /**
+ * Return the full seed for the spec.
+ *
+ * @return a copy of the seed.
+ */
+ public byte[] getSeed()
+ {
+ return Arrays.clone(seed);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
index 4a1a92a5..025327f6 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
@@ -1,6 +1,3 @@
-/***************************************************************/
-/****** DO NOT EDIT THIS CLASS bc-java SOURCE FILE ******/
-/***************************************************************/
package org.bouncycastle.jcajce.util;
import java.io.IOException;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
index 40087612..25897cf5 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
@@ -11,15 +11,23 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class BCJcaJceHelper
extends ProviderJcaJceHelper
{
+ private static volatile Provider bcProvider;
+
private static Provider getBouncyCastleProvider()
{
if (Security.getProvider("BC") != null)
{
return Security.getProvider("BC");
}
+ else if (bcProvider != null)
+ {
+ return bcProvider;
+ }
else
{
- return new BouncyCastleProvider();
+ bcProvider = new BouncyCastleProvider();
+
+ return bcProvider;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
index 27ca55ae..426efc09 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
@@ -6,6 +6,7 @@ import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -96,4 +97,10 @@ public class DefaultJcaJceHelper
{
return CertificateFactory.getInstance(algorithm);
}
+
+ public SecureRandom createSecureRandom(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return SecureRandom.getInstance(algorithm);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
index 7a78193e..aa151cce 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
@@ -7,6 +7,7 @@ import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -59,4 +60,7 @@ public interface JcaJceHelper
CertificateFactory createCertificateFactory(String algorithm)
throws NoSuchProviderException, CertificateException;
+
+ SecureRandom createSecureRandom(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
index 1bf8b31b..bad54afc 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -34,6 +34,10 @@ public class MessageDigestUtils
digestOidMap.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411");
digestOidMap.put(GNUObjectIdentifiers.Tiger_192, "Tiger");
digestOidMap.put(ISOIECObjectIdentifiers.whirlpool, "Whirlpool");
+ digestOidMap.put(NISTObjectIdentifiers.id_sha3_224, "SHA3-224");
+ digestOidMap.put(NISTObjectIdentifiers.id_sha3_256, "SHA3-256");
+ digestOidMap.put(NISTObjectIdentifiers.id_sha3_384, "SHA3-384");
+ digestOidMap.put(NISTObjectIdentifiers.id_sha3_512, "SHA3-512");
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
index 280539d5..bc5da9a9 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
@@ -7,6 +7,7 @@ import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -103,4 +104,10 @@ public class NamedJcaJceHelper
{
return CertificateFactory.getInstance(algorithm, providerName);
}
+
+ public SecureRandom createSecureRandom(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return SecureRandom.getInstance(algorithm, providerName);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
index fb4b9a73..f07b0a85 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
@@ -7,6 +7,7 @@ import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -103,4 +104,10 @@ public class ProviderJcaJceHelper
{
return CertificateFactory.getInstance(algorithm, provider);
}
+
+ public SecureRandom createSecureRandom(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return SecureRandom.getInstance(algorithm, provider);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index 8af487d1..a490c615 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -44,7 +44,7 @@ import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
public final class BouncyCastleProvider extends Provider
implements ConfigurableProvider
{
- private static String info = "BouncyCastle Security Provider v1.54";
+ private static String info = "BouncyCastle Security Provider v1.56";
public static final String PROVIDER_NAME = "BC";
@@ -59,12 +59,12 @@ public final class BouncyCastleProvider extends Provider
private static final String[] SYMMETRIC_GENERIC =
{
- "PBEPBKDF2", "PBEPKCS12"
+ "PBEPBKDF2", "PBEPKCS12", "TLSKDF"
};
private static final String[] SYMMETRIC_MACS =
{
- "SipHash"
+ "SipHash", "Poly1305"
};
private static final String[] SYMMETRIC_CIPHERS =
@@ -108,7 +108,16 @@ public final class BouncyCastleProvider extends Provider
private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore.";
private static final String[] KEYSTORES =
{
- "BC", "PKCS12"
+ "BC", "BCFKS", "PKCS12"
+ };
+
+ /*
+ * Configurable secure random
+ */
+ private static final String SECURE_RANDOM_PACKAGE = "org.bouncycastle.jcajce.provider.drbg.";
+ private static final String[] SECURE_RANDOMS =
+ {
+ "DRBG"
};
/**
@@ -118,7 +127,7 @@ public final class BouncyCastleProvider extends Provider
*/
public BouncyCastleProvider()
{
- super(PROVIDER_NAME, 1.54, info);
+ super(PROVIDER_NAME, 1.56, info);
AccessController.doPrivileged(new PrivilegedAction()
{
@@ -146,6 +155,8 @@ public final class BouncyCastleProvider extends Provider
loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
+ loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS);
+
//
// X509Store
//
@@ -259,13 +270,24 @@ public final class BouncyCastleProvider extends Provider
public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
{
- keyInfoConverters.put(oid, keyInfoConverter);
+ synchronized (keyInfoConverters)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+ }
+
+ private static AsymmetricKeyInfoConverter getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm)
+ {
+ synchronized (keyInfoConverters)
+ {
+ return (AsymmetricKeyInfoConverter)keyInfoConverters.get(algorithm);
+ }
}
public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
throws IOException
{
- AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+ AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(publicKeyInfo.getAlgorithm().getAlgorithm());
if (converter == null)
{
@@ -278,7 +300,7 @@ public final class BouncyCastleProvider extends Provider
public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
throws IOException
{
- AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+ AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
if (converter == null)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
index cda05e83..f89b9fd7 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -1,6 +1,11 @@
package org.bouncycastle.jce.provider;
import java.security.Permission;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
import javax.crypto.spec.DHParameterSpec;
@@ -21,12 +26,18 @@ class BouncyCastleProviderConfiguration
BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+ private static Permission BC_EC_CURVE_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ACCEPTABLE_EC_CURVES);
+ private static Permission BC_ADDITIONAL_EC_CURVE_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ADDITIONAL_EC_PARAMETERS);
private ThreadLocal ecThreadSpec = new ThreadLocal();
private ThreadLocal dhThreadSpec = new ThreadLocal();
private volatile ECParameterSpec ecImplicitCaParams;
private volatile Object dhDefaultParams;
+ private volatile Set acceptableNamedCurves = new HashSet();
+ private volatile Map additionalECParameters = new HashMap();
void setParameter(String parameterName, Object parameter)
{
@@ -118,6 +129,24 @@ class BouncyCastleProviderConfiguration
throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
}
}
+ else if (parameterName.equals(ConfigurableProvider.ACCEPTABLE_EC_CURVES))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_CURVE_PERMISSION);
+ }
+
+ this.acceptableNamedCurves = (Set)parameter;
+ }
+ else if (parameterName.equals(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_ADDITIONAL_EC_CURVE_PERMISSION);
+ }
+
+ this.additionalECParameters = (Map)parameter;
+ }
}
public ECParameterSpec getEcImplicitlyCa()
@@ -164,4 +193,14 @@ class BouncyCastleProviderConfiguration
return null;
}
+
+ public Set getAcceptableNamedCurves()
+ {
+ return Collections.unmodifiableSet(acceptableNamedCurves);
+ }
+
+ public Map getAdditionalECParameters()
+ {
+ return Collections.unmodifiableMap(additionalECParameters);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java
index e6186f67..c907085a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java
@@ -42,7 +42,7 @@ public class BrokenKDF2BytesGenerator
{
if (!(param instanceof KDFParameters))
{
- throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ throw new IllegalArgumentException("KDF parameters required for generator");
}
KDFParameters p = (KDFParameters)param;
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
index b6885ace..b8308207 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -53,6 +53,7 @@ import org.bouncycastle.util.encoders.Hex;
* CRL Number
* Delta CRL Indicator (critical)
* Issuing Distribution Point (critical)
+ * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory.
*/
public class X509CRLObject
extends X509CRL
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertParser.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertParser.java
index 0663735b..9ff1765b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertParser.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertParser.java
@@ -19,6 +19,9 @@ import org.bouncycastle.asn1.pkcs.SignedData;
import org.bouncycastle.x509.X509StreamParserSpi;
import org.bouncycastle.x509.util.StreamParsingException;
+/**
+ * @deprecated use CertificateFactory or the PEMParser in the openssl package (pkix jar).
+ */
public class X509CertParser
extends X509StreamParserSpi
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
index bd4d6930..e204be77 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -66,6 +66,9 @@ import org.bouncycastle.util.Integers;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
+/**
+ * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory.
+ */
public class X509CertificateObject
extends X509Certificate
implements PKCS12BagAttributeCarrier
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AEADTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AEADTest.java
index 92c07e52..a8f7c26f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AEADTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AEADTest.java
@@ -18,7 +18,9 @@ import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import junit.framework.TestCase;
import org.bouncycastle.asn1.cms.GCMParameters;
+import org.bouncycastle.jcajce.spec.AEADParameterSpec;
import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
@@ -57,6 +59,7 @@ public class AEADTest extends SimpleTest
catch (ClassNotFoundException e)
{
}
+ testAEADParameterSpec(K2, N2, A2, P2, C2);
if (aeadAvailable)
{
checkCipherWithAD(K2, N2, A2, P2, C2_short);
@@ -64,6 +67,7 @@ public class AEADTest extends SimpleTest
testGCMParameterSpecWithRepeatKey(K2, N2, A2, P2, C2);
testGCMGeneric(KGCM, NGCM, new byte[0], new byte[0], CGCM);
testGCMParameterSpecWithMultipleUpdates(K2, N2, A2, P2, C2);
+ testRepeatedGCMWithSpec(KGCM, NGCM, A2, P2, Hex.decode("f4732d84342623f65b7d63c3c335dd44b87d"));
}
else
{
@@ -139,6 +143,74 @@ public class AEADTest extends SimpleTest
}
}
+ private void testAEADParameterSpec(byte[] K,
+ byte[] N,
+ byte[] A,
+ byte[] P,
+ byte[] C)
+ throws Exception
+ {
+ Cipher eax = Cipher.getInstance("AES/EAX/NoPadding", "BC");
+ SecretKeySpec key = new SecretKeySpec(K, "AES");
+
+ AEADParameterSpec spec = new AEADParameterSpec(N, 128, A);
+ eax.init(Cipher.ENCRYPT_MODE, key, spec);
+
+ byte[] c = eax.doFinal(P);
+
+ if (!Arrays.areEqual(C, c))
+ {
+ TestCase.fail("JCE encrypt with additional data and AEADParameterSpec failed.");
+ }
+
+ // doFinal test
+ c = eax.doFinal(P);
+
+ if (!Arrays.areEqual(C, c))
+ {
+ TestCase.fail("JCE encrypt with additional data and AEADParameterSpec failed after do final");
+ }
+
+ eax.init(Cipher.DECRYPT_MODE, key, spec);
+
+ byte[] p = eax.doFinal(C);
+
+ if (!Arrays.areEqual(P, p))
+ {
+ TestCase.fail("JCE decrypt with additional data and AEADParameterSpec failed.");
+ }
+
+ AlgorithmParameters algParams = eax.getParameters();
+
+ byte[] encParams = algParams.getEncoded();
+
+ GCMParameters gcmParameters = GCMParameters.getInstance(encParams);
+
+ if (!Arrays.areEqual(spec.getIV(), gcmParameters.getNonce()) || spec.getMacSizeInBits() != gcmParameters.getIcvLen() * 8)
+ {
+ TestCase.fail("parameters mismatch");
+ }
+
+ // note: associated data is not preserved
+ AEADParameterSpec cSpec = algParams.getParameterSpec(AEADParameterSpec.class);
+ if (!Arrays.areEqual(spec.getIV(), cSpec.getNonce()) || spec.getMacSizeInBits() != cSpec.getMacSizeInBits()
+ || cSpec.getAssociatedData() != null)
+ {
+ TestCase.fail("parameters mismatch");
+ }
+
+ AlgorithmParameters aeadParams = AlgorithmParameters.getInstance("GCM", "BC");
+
+ aeadParams.init(spec);
+
+ cSpec = aeadParams.getParameterSpec(AEADParameterSpec.class);
+ if (!Arrays.areEqual(spec.getIV(), cSpec.getNonce()) || spec.getMacSizeInBits() != cSpec.getMacSizeInBits()
+ || cSpec.getAssociatedData() != null)
+ {
+ TestCase.fail("parameters mismatch");
+ }
+ }
+
private void testGCMParameterSpec(byte[] K,
byte[] N,
byte[] A,
@@ -346,6 +418,69 @@ public class AEADTest extends SimpleTest
}
}
+ private void testRepeatedGCMWithSpec(byte[] K,
+ byte[] N,
+ byte[] A,
+ byte[] P,
+ byte[] C)
+ throws InvalidKeyException, NoSuchAlgorithmException,
+ NoSuchPaddingException, IllegalBlockSizeException,
+ BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IOException
+ {
+ Cipher eax = Cipher.getInstance("AES/GCM/NoPadding", "BC");
+ SecretKeySpec key = new SecretKeySpec(K, "AES");
+ GCMParameterSpec spec = new GCMParameterSpec(128, N);
+ eax.init(Cipher.ENCRYPT_MODE, key, spec);
+
+ eax.updateAAD(A);
+ byte[] c = eax.doFinal(P);
+
+ if (!areEqual(C, c))
+ {
+ fail("JCE encrypt with additional data and RepeatedSecretKeySpec failed.");
+ }
+
+ eax = Cipher.getInstance("GCM", "BC");
+ eax.init(Cipher.DECRYPT_MODE, key, spec);
+ eax.updateAAD(A);
+ byte[] p = eax.doFinal(C);
+
+ if (!areEqual(P, p))
+ {
+ fail("JCE decrypt with additional data and GCMParameterSpec failed.");
+ }
+
+ try
+ {
+ eax.init(Cipher.ENCRYPT_MODE, new RepeatedSecretKeySpec("AES"), spec);
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage()));
+ }
+
+ try
+ {
+ eax.init(Cipher.ENCRYPT_MODE, new RepeatedSecretKeySpec("AES"), new IvParameterSpec(spec.getIV()));
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage()));
+ }
+
+ try
+ {
+ eax.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(K, "AES"), new IvParameterSpec(spec.getIV()));
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage()));
+ }
+ }
+
public static void main(String[] args) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java
index 02b7b927..217258a3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java
@@ -105,9 +105,9 @@ public class AlgorithmParametersTest
AlgorithmParameters al = AlgorithmParameters.getInstance("EC", "BC");
- al.init(new ECGenParameterSpec(SECObjectIdentifiers.secp224k1.getId()));
+ al.init(new ECGenParameterSpec(SECObjectIdentifiers.secp256r1.getId()));
- if (!Arrays.areEqual(Hex.decode("06052b81040020"), al.getEncoded()))
+ if (!Arrays.areEqual(Hex.decode("06082a8648ce3d030107"), al.getEncoded()))
{
fail("EC param test failed");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java
new file mode 100644
index 00000000..1a564716
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java
@@ -0,0 +1,781 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.util.Date;
+import java.util.Enumeration;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * Exercise the BCFKS KeyStore,
+ */
+public class BCFKSStoreTest
+ extends SimpleTest
+{
+ private static byte[] trustedCertData = Base64.decode(
+ "MIIB/DCCAaagAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIE" +
+ "JvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExJjAkBgkqhkiG9w0BCQEWF2lzc3VlckBi" +
+ "b3VuY3ljYXN0bGUub3JnMB4XDTE0MDIyODExMjcxMVoXDTE0MDQyOTExMjcxMVowgYcxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaG" +
+ "UgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMScwJQYJKoZI" +
+ "hvcNAQkBFhhzdWJqZWN0QGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5" +
+ "hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBETANBgkqhkiG9w0BAQQFAANBAJ/ZhfF21NykhbEY" +
+ "RQrAo/yRr9XfpmBTVUSlLJXYoNVVRT5u9SGQqmPNfHElrTvNMZQPC0ridDZtBWb6S2tg9/E=");
+
+ static char[] testPassword = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
+ static char[] invalidTestPassword = {'Y', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
+
+
+ public void shouldCreateEmptyBCFKSNoPassword()
+ throws Exception
+ {
+ checkEmptyStore(null);
+ }
+
+ public void shouldCreateEmptyBCFKSPassword()
+ throws Exception
+ {
+ checkEmptyStore(testPassword);
+ }
+
+ private void checkEmptyStore(char[] passwd)
+ throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ isTrue("", 0 == store1.size());
+ isTrue("", !store1.aliases().hasMoreElements());
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", 0 == store2.size());
+ isTrue("", !store2.aliases().hasMoreElements());
+
+ checkInvalidLoad(store2, passwd, bOut.toByteArray());
+ }
+
+ private void checkInvalidLoad(KeyStore store, char[] passwd, byte[] data)
+ throws NoSuchAlgorithmException, CertificateException, KeyStoreException
+ {
+ checkInvalidLoadForPassword(store, invalidTestPassword, data);
+
+ if (passwd != null)
+ {
+ checkInvalidLoadForPassword(store, null, data);
+ }
+ }
+
+ private void checkInvalidLoadForPassword(KeyStore store, char[] password, byte[] data)
+ throws NoSuchAlgorithmException, CertificateException, KeyStoreException
+ {
+ try
+ {
+ store.load(new ByteArrayInputStream(data), password);
+ }
+ catch (IOException e)
+ {
+ isTrue("wrong message", "BCFKS KeyStore corrupted: MAC calculation failed.".equals(e.getMessage()));
+ }
+
+ isTrue("", 0 == store.size());
+ isTrue("", !store.aliases().hasMoreElements());
+ }
+
+ public void shouldStoreOneCertificate()
+ throws Exception
+ {
+ X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData));
+
+ checkOneCertificate(cert, null);
+ checkOneCertificate(cert, testPassword);
+ }
+
+ private void checkOneCertificate(X509Certificate cert, char[] passwd)
+ throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ store1.setCertificateEntry("cert", cert);
+
+ isTrue("", 1 == store1.size());
+ Enumeration<String> en1 = store1.aliases();
+
+ isTrue("", "cert".equals(en1.nextElement()));
+ isTrue("", !en1.hasMoreElements());
+
+ certStorageCheck(store1, "cert", cert);
+
+ Date entryDate = store1.getCreationDate("cert");
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", entryDate.equals(store2.getCreationDate("cert")));
+ isTrue("", 1 == store2.size());
+ Enumeration<String> en2 = store2.aliases();
+
+ isTrue("", "cert".equals(en2.nextElement()));
+ isTrue("", !en2.hasMoreElements());
+
+ certStorageCheck(store2, "cert", cert);
+
+ // check invalid load with content
+
+ checkInvalidLoad(store2, passwd, bOut.toByteArray());
+
+ // check deletion on purpose
+
+ store1.deleteEntry("cert");
+
+ isTrue("", 0 == store1.size());
+ isTrue("", !store1.aliases().hasMoreElements());
+
+ bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", 0 == store2.size());
+ isTrue("", !store2.aliases().hasMoreElements());
+ }
+
+ public void shouldStoreOnePrivateKey()
+ throws Exception
+ {
+ PrivateKey privKey = getPrivateKey();
+
+ X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData));
+
+ checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, null);
+ checkOnePrivateKeyFips(privKey, new X509Certificate[] { cert }, testPassword);
+ checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, null);
+ checkOnePrivateKeyDef(privKey, new X509Certificate[] { cert }, testPassword);
+ }
+
+ public void shouldStoreOnePrivateKeyWithChain()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
+
+ kpGen.initialize(512);
+
+ KeyPair kp1 = kpGen.generateKeyPair();
+ KeyPair kp2 = kpGen.generateKeyPair();
+
+ X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2);
+ X509Certificate interCert = TestUtils.createCert(
+ TestUtils.getCertSubject(finalCert),
+ kp2.getPrivate(),
+ "CN=EE",
+ "SHA1withRSA",
+ null,
+ kp1.getPublic());
+
+ checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null);
+ checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword);
+
+ checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null);
+ checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword);
+ }
+
+ public void shouldStoreOneECKeyWithChain()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
+
+ kpGen.initialize(256);
+
+ KeyPair kp1 = kpGen.generateKeyPair();
+ KeyPair kp2 = kpGen.generateKeyPair();
+
+ X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withECDSA", kp2);
+ X509Certificate interCert = TestUtils.createCert(
+ TestUtils.getCertSubject(finalCert),
+ kp2.getPrivate(),
+ "CN=EE",
+ "SHA1withECDSA",
+ null,
+ kp1.getPublic());
+
+ checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null);
+ checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword);
+
+ checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null);
+ checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword);
+ }
+
+ public void shouldRejectInconsistentKeys()
+ throws Exception
+ {
+ PrivateKey privKey = getPrivateKey();
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
+
+ X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin));
+
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ try
+ {
+ store1.setKeyEntry("privkey", privKey, "hello".toCharArray(), new X509Certificate[]{interCert});
+ fail("no exception");
+ }
+ catch (KeyStoreException e)
+ {
+ isTrue("", "RSA keys do not have the same modulus".equals(e.getCause().getMessage()));
+ }
+ }
+
+ private void checkOnePrivateKeyFips(PrivateKey key, X509Certificate[] certs, char[] passwd)
+ throws Exception
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ checkOnePrivateKey(key, store1, certs, passwd);
+ }
+
+ private void checkOnePrivateKeyDef(PrivateKey key, X509Certificate[] certs, char[] passwd)
+ throws Exception
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS-DEF", "BC");
+
+ store1.load(null, null);
+
+ checkOnePrivateKey(key, store1, certs, passwd);
+ }
+
+ private void checkOnePrivateKey(PrivateKey key, KeyStore store1, X509Certificate[] certs, char[] passwd)
+ throws Exception
+ {
+ store1.setKeyEntry("privkey", key, passwd, certs);
+
+ isTrue("", 1 == store1.size());
+ Enumeration<String> en1 = store1.aliases();
+
+ isTrue("", "privkey".equals(en1.nextElement()));
+ isTrue("", !en1.hasMoreElements());
+
+ privateKeyStorageCheck(store1, "privkey", key, certs[0], passwd);
+
+ Date entryDate = store1.getCreationDate("privkey");
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", store2.getCertificateChain("privkey").length == certs.length);
+ Certificate[] sChain = store2.getCertificateChain("privkey");
+ for (int i = 0; i != sChain.length; i++)
+ {
+ isTrue("", certs[i].equals(sChain[i]));
+ }
+ isTrue("", entryDate.equals(store2.getCreationDate("privkey")));
+ isTrue("", 1 == store2.size());
+ Enumeration<String> en2 = store2.aliases();
+
+ isTrue("", "privkey".equals(en2.nextElement()));
+ isTrue("", !en2.hasMoreElements());
+
+ privateKeyStorageCheck(store2, "privkey", key, certs[0], passwd);
+
+ // check invalid load with content
+
+ checkInvalidLoad(store2, passwd, bOut.toByteArray());
+
+ // check deletion on purpose
+
+ store1.deleteEntry("privkey");
+
+ isTrue("", 0 == store1.size());
+ isTrue("", !store1.aliases().hasMoreElements());
+
+ bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", 0 == store2.size());
+ isTrue("", !store2.aliases().hasMoreElements());
+ }
+
+ public void shouldStoreMultipleKeys()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
+
+ kpGen.initialize(512);
+
+ KeyPair kp1 = kpGen.generateKeyPair();
+ KeyPair kp2 = kpGen.generateKeyPair();
+
+ X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2);
+ X509Certificate interCert = TestUtils.createCert(
+ TestUtils.getCertSubject(finalCert),
+ kp2.getPrivate(),
+ "CN=EE",
+ "SHA1withRSA",
+ null,
+ kp1.getPublic());
+
+ PrivateKey privKey = kp1.getPrivate();
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
+
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData));
+
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ store1.setKeyEntry("privkey", privKey, testPassword, new X509Certificate[]{interCert, finalCert});
+ store1.setCertificateEntry("trusted", cert);
+ SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES");
+ store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null);
+ SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede");
+ store1.setKeyEntry("secret2", edeKey, "secretPwd2".toCharArray(), null);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, testPassword);
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword);
+
+ isTrue("", 4 ==store2.size());
+
+ Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray());
+
+ isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm()));
+
+ isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded()));
+
+ Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray());
+ isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded()));
+ isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm()));
+
+ Key storePrivKey = store2.getKey("privkey", testPassword);
+ isTrue("", privKey.equals(storePrivKey));
+ isTrue("", 2 == store2.getCertificateChain("privkey").length);
+
+ Certificate storeCert = store2.getCertificate("trusted");
+ isTrue("", cert.equals(storeCert));
+
+ isTrue("", null ==store2.getCertificate("unknown"));
+
+ isTrue("", null ==store2.getCertificateChain("unknown"));
+
+ isTrue("", !store2.isCertificateEntry("unknown"));
+
+ isTrue("", !store2.isKeyEntry("unknown"));
+
+ isTrue("", !store2.containsAlias("unknown"));
+ }
+
+ public void shouldStoreSecretKeys()
+ throws Exception
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES");
+ SecretKeySpec edeKey1 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede");
+ SecretKeySpec edeKey2 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TripleDES");
+ SecretKeySpec edeKey3 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TDEA");
+ SecretKeySpec hmacKey1 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA1");
+ SecretKeySpec hmacKey224 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA224");
+ SecretKeySpec hmacKey256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff01ff"), "HmacSHA256");
+ SecretKeySpec hmacKey384 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff0102ff"), "HmacSHA384");
+ SecretKeySpec hmacKey512 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff010203ff"), "HmacSHA512");
+
+ store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null);
+ store1.setKeyEntry("secret2", edeKey1, "secretPwd2".toCharArray(), null);
+ store1.setKeyEntry("secret3", edeKey2, "secretPwd3".toCharArray(), null);
+ store1.setKeyEntry("secret4", edeKey3, "secretPwd4".toCharArray(), null);
+ store1.setKeyEntry("secret5", hmacKey1, "secretPwd5".toCharArray(), null);
+ store1.setKeyEntry("secret6", hmacKey224, "secretPwd6".toCharArray(), null);
+ store1.setKeyEntry("secret7", hmacKey256, "secretPwd7".toCharArray(), null);
+ store1.setKeyEntry("secret8", hmacKey384, "secretPwd8".toCharArray(), null);
+ store1.setKeyEntry("secret9", hmacKey512, "secretPwd9".toCharArray(), null);
+
+ checkSecretKey(store1, "secret1", "secretPwd1".toCharArray(), aesKey);
+ checkSecretKey(store1, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE
+ checkSecretKey(store1, "secret3", "secretPwd3".toCharArray(), edeKey1);
+ checkSecretKey(store1, "secret4", "secretPwd4".toCharArray(), edeKey1);
+ checkSecretKey(store1, "secret5", "secretPwd5".toCharArray(), hmacKey1);
+ checkSecretKey(store1, "secret6", "secretPwd6".toCharArray(), hmacKey224);
+ checkSecretKey(store1, "secret7", "secretPwd7".toCharArray(), hmacKey256);
+ checkSecretKey(store1, "secret8", "secretPwd8".toCharArray(), hmacKey384);
+ checkSecretKey(store1, "secret9", "secretPwd9".toCharArray(), hmacKey512);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, "secretkeytest".toCharArray());
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), "secretkeytest".toCharArray());
+
+ checkSecretKey(store2, "secret1", "secretPwd1".toCharArray(), aesKey);
+ checkSecretKey(store2, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE
+ checkSecretKey(store2, "secret3", "secretPwd3".toCharArray(), edeKey1);
+ checkSecretKey(store2, "secret4", "secretPwd4".toCharArray(), edeKey1);
+ checkSecretKey(store2, "secret5", "secretPwd5".toCharArray(), hmacKey1);
+ checkSecretKey(store2, "secret6", "secretPwd6".toCharArray(), hmacKey224);
+ checkSecretKey(store2, "secret7", "secretPwd7".toCharArray(), hmacKey256);
+ checkSecretKey(store2, "secret8", "secretPwd8".toCharArray(), hmacKey384);
+ checkSecretKey(store2, "secret9", "secretPwd9".toCharArray(), hmacKey512);
+
+ isTrue("", null ==store2.getKey("secret10", new char[0]));
+ }
+
+ private void checkSecretKey(KeyStore store, String alias, char[] passwd, SecretKey key)
+ throws Exception
+ {
+ SecretKey sKey = (SecretKey)store.getKey(alias, passwd);
+
+ isTrue("", Arrays.areEqual(key.getEncoded(), sKey.getEncoded()));
+ isTrue("", key.getAlgorithm().equals(sKey.getAlgorithm()));
+
+ if (!store.isKeyEntry(alias))
+ {
+ fail("key not identified as key entry");
+ }
+ if (!store.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class))
+ {
+ fail("not identified as key entry via SecretKeyEntry");
+ }
+ }
+
+ private PrivateKey getPrivateKey()
+ {
+ PrivateKey privKey = null;
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16),
+ new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+ new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+ new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+ new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+ new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+ new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+
+ try
+ {
+ KeyFactory fact = KeyFactory.getInstance("RSA", "BC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ }
+
+ return privKey;
+ }
+
+ public void shouldStoreOneSecretKey()
+ throws Exception
+ {
+ checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), null);
+ checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), testPassword);
+ }
+
+ private void checkOneSecretKey(SecretKey key, char[] passwd)
+ throws Exception
+ {
+ KeyStore store1 = KeyStore.getInstance("BCFKS", "BC");
+
+ store1.load(null, null);
+
+ store1.setKeyEntry("seckey", key, passwd, null);
+
+ isTrue("", 1 == store1.size());
+ Enumeration<String> en1 = store1.aliases();
+
+ isTrue("", "seckey".equals(en1.nextElement()));
+ isTrue("", !en1.hasMoreElements());
+
+ secretKeyStorageCheck(store1, "seckey", key, passwd);
+
+ Date entryDate = store1.getCreationDate("seckey");
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ KeyStore store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", entryDate.equals(store2.getCreationDate("seckey")));
+ isTrue("", 1 == store2.size());
+ Enumeration<String> en2 = store2.aliases();
+
+ isTrue("", "seckey".equals(en2.nextElement()));
+ isTrue("", !en2.hasMoreElements());
+
+ secretKeyStorageCheck(store2, "seckey", key, passwd);
+
+ // check invalid load with content
+
+ checkInvalidLoad(store2, passwd, bOut.toByteArray());
+
+ // check deletion on purpose
+
+ store1.deleteEntry("seckey");
+
+ isTrue("", 0 == store1.size());
+ isTrue("", !store1.aliases().hasMoreElements());
+
+ bOut = new ByteArrayOutputStream();
+
+ store1.store(bOut, passwd);
+
+ store2 = KeyStore.getInstance("BCFKS", "BC");
+
+ store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ isTrue("", 0 == store2.size());
+ isTrue("", !store2.aliases().hasMoreElements());
+ }
+
+ private void privateKeyStorageCheck(KeyStore store, String keyName, PrivateKey key, Certificate cert, char[] password)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException
+ {
+ if (!store.containsAlias(keyName))
+ {
+ fail("couldn't find alias privateKey");
+ }
+
+ if (store.isCertificateEntry(keyName))
+ {
+ fail("key identified as certificate entry");
+ }
+
+ if (!store.isKeyEntry(keyName))
+ {
+ fail("key not identified as key entry");
+ }
+
+ Key storeKey = store.getKey(keyName, password);
+
+ if (store.getType().equals("BCFKS"))
+ {
+ isTrue("", key.equals(storeKey));
+ }
+
+ if (password != null)
+ {
+ try
+ {
+ store.getKey(keyName, null);
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ isTrue("",e.getMessage().startsWith("BCFKS KeyStore unable to recover private key (privkey)"));
+ }
+ }
+
+ Certificate[] certificateChain = store.getCertificateChain(keyName);
+ if (certificateChain == null)
+ {
+ fail("Did not return certificate chain");
+ }
+ isTrue("", cert.equals(certificateChain[0]));
+
+ isTrue("", keyName.equals(store.getCertificateAlias(cert)));
+
+ if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class))
+ {
+ fail("identified as TrustedCertificateEntry");
+ }
+
+ if (!store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class))
+ {
+ fail("not identified as key entry via PrivateKeyEntry");
+ }
+
+ if (store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class))
+ {
+ fail("identified as key entry via SecretKeyEntry");
+ }
+ }
+
+ private void certStorageCheck(KeyStore store, String certName, Certificate cert)
+ throws KeyStoreException
+ {
+ if (!store.containsAlias(certName))
+ {
+ fail("couldn't find alias " + certName);
+ }
+
+ if (!store.isCertificateEntry(certName))
+ {
+ fail("cert not identified as certificate entry");
+ }
+
+ if (store.isKeyEntry(certName))
+ {
+ fail("cert identified as key entry");
+ }
+
+ if (!store.entryInstanceOf(certName, KeyStore.TrustedCertificateEntry.class))
+ {
+ fail("cert not identified as TrustedCertificateEntry");
+ }
+
+ if (store.entryInstanceOf(certName, KeyStore.PrivateKeyEntry.class))
+ {
+ fail("cert identified as key entry via PrivateKeyEntry");
+ }
+
+ if (store.entryInstanceOf(certName, KeyStore.SecretKeyEntry.class))
+ {
+ fail("cert identified as key entry via SecretKeyEntry");
+ }
+
+ if (!certName.equals(store.getCertificateAlias(cert)))
+ {
+ fail("Did not return alias for certificate entry");
+ }
+ }
+
+ private void secretKeyStorageCheck(KeyStore store, String keyName, SecretKey key, char[] password)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException
+ {
+ if (!store.containsAlias(keyName))
+ {
+ fail("couldn't find alias privateKey");
+ }
+
+ if (store.isCertificateEntry(keyName))
+ {
+ fail("key identified as certificate entry");
+ }
+
+ if (!store.isKeyEntry(keyName))
+ {
+ fail("key not identified as key entry");
+ }
+
+ Key storeKey = store.getKey(keyName, password);
+
+ isTrue("", Arrays.areEqual(key.getEncoded(), storeKey.getEncoded()));
+
+ if (password != null)
+ {
+ try
+ {
+ store.getKey(keyName, null);
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover secret key (seckey)"));
+ }
+ }
+
+ Certificate[] certificateChain = store.getCertificateChain(keyName);
+ if (certificateChain != null)
+ {
+ fail("returned certificates!");
+ }
+
+ if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class))
+ {
+ fail("identified as TrustedCertificateEntry");
+ }
+
+ if (store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class))
+ {
+ fail("identified as key entry via PrivateKeyEntry");
+ }
+
+ if (!store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class))
+ {
+ fail("not identified as key entry via SecretKeyEntry");
+ }
+ }
+
+ public String getName()
+ {
+ return "BCFKS";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ shouldCreateEmptyBCFKSNoPassword();
+ shouldCreateEmptyBCFKSPassword();
+ shouldStoreMultipleKeys();
+ shouldStoreOneCertificate();
+ shouldStoreOneECKeyWithChain();
+ shouldStoreOnePrivateKey();
+ shouldStoreOnePrivateKeyWithChain();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new BCFKSStoreTest());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java
index ea1e2fa0..eccf3858 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java
@@ -4,6 +4,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -923,6 +925,8 @@ public class BlockCipherTest
}
}
}
+
+ serialiseTest(algorithm, input, output);
}
catch (TestFailedException e)
{
@@ -932,7 +936,216 @@ public class BlockCipherTest
{
fail("" + algorithm + " failed short buffer decryption - " + e.toString());
}
- }
+ }
+
+ private void serialiseTest(
+ String algorithm,
+ byte[] input,
+ byte[] output)
+ throws Exception
+ {
+ Key key = null;
+ KeyGenerator keyGen;
+ SecureRandom rand;
+ Cipher in = null;
+ Cipher out = null;
+ CipherInputStream cIn;
+ CipherOutputStream cOut;
+ ByteArrayInputStream bIn;
+ ByteArrayOutputStream bOut;
+
+ rand = new FixedSecureRandom();
+
+ String baseAlgorithm, mode;
+ int index = algorithm.indexOf('/');
+
+ if (index > 0)
+ {
+ baseAlgorithm = algorithm.substring(0, index);
+ mode = algorithm.substring(index + 1, algorithm.lastIndexOf('/'));
+ }
+ else
+ {
+ baseAlgorithm = algorithm;
+ mode = null;
+ }
+
+ keyGen = KeyGenerator.getInstance(baseAlgorithm, "BC");
+ if (!keyGen.getAlgorithm().equals(baseAlgorithm))
+ {
+ fail("wrong key generator returned!");
+ }
+ keyGen.init(rand);
+
+ key = keyGen.generateKey();
+
+ bOut = new ByteArrayOutputStream();
+ ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+
+ oOut.writeObject(key);
+
+ bIn = new ByteArrayInputStream(bOut.toByteArray());
+ ObjectInputStream oIn = new ObjectInputStream(bIn);
+
+ in = Cipher.getInstance(algorithm, "BC");
+ out = Cipher.getInstance(algorithm, "BC");
+
+ key = (Key)oIn.readObject();
+
+ if (!in.getAlgorithm().startsWith(baseAlgorithm))
+ {
+ fail("wrong cipher returned!");
+ }
+
+ if (algorithm.startsWith("RC2"))
+ {
+ if (baseAlgorithm.equals(algorithm) || algorithm.indexOf("ECB") > 0)
+ {
+ out.init(Cipher.ENCRYPT_MODE, key, new RC2ParameterSpec(rc2Spec.getEffectiveKeyBits()), rand);
+ }
+ else
+ {
+ out.init(Cipher.ENCRYPT_MODE, key, rc2Spec, rand);
+ }
+ }
+ else if (algorithm.startsWith("RC5"))
+ {
+ if (algorithm.startsWith("RC5-64"))
+ {
+ out.init(Cipher.ENCRYPT_MODE, key, rc564Spec, rand);
+ }
+ else
+ {
+ out.init(Cipher.ENCRYPT_MODE, key, rc5Spec, rand);
+ }
+ }
+ else
+ {
+ out.init(Cipher.ENCRYPT_MODE, key, rand);
+ }
+
+ //
+ // grab the iv if there is one
+ //
+ if (algorithm.startsWith("RC2"))
+ {
+ if (baseAlgorithm.equals(algorithm) || algorithm.indexOf("ECB") > 0)
+ {
+ in.init(Cipher.DECRYPT_MODE, key, new RC2ParameterSpec(rc2Spec.getEffectiveKeyBits()), rand);
+ }
+ else
+ {
+ in.init(Cipher.DECRYPT_MODE, key, rc2Spec, rand);
+ }
+ }
+ else if (algorithm.startsWith("RC5"))
+ {
+ if (algorithm.startsWith("RC5-64"))
+ {
+ in.init(Cipher.DECRYPT_MODE, key, rc564Spec, rand);
+ }
+ else
+ {
+ in.init(Cipher.DECRYPT_MODE, key, rc5Spec, rand);
+ }
+ }
+ else
+ {
+ byte[] iv;
+
+ iv = out.getIV();
+ if (iv != null)
+ {
+ if (!shortIvOkay.contains(mode))
+ {
+ try
+ {
+ byte[] nIv = new byte[iv.length - 1];
+
+ in.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(nIv));
+ fail("failed to pick up short IV");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // ignore - this is what we want...
+ }
+ }
+
+ IvParameterSpec spec;
+
+ spec = new IvParameterSpec(iv);
+
+ in.init(Cipher.DECRYPT_MODE, key, spec);
+ }
+ else
+ {
+ in.init(Cipher.DECRYPT_MODE, key);
+ }
+ }
+
+ //
+ // encryption pass
+ //
+ bOut = new ByteArrayOutputStream();
+
+ cOut = new CipherOutputStream(bOut, out);
+
+ try
+ {
+ for (int i = 0; i != input.length / 2; i++)
+ {
+ cOut.write(input[i]);
+ }
+
+ cOut.write(input, input.length / 2, input.length - input.length / 2);
+ cOut.close();
+ }
+ catch (IOException e)
+ {
+ fail("" + algorithm + " failed encryption - " + e.toString());
+ }
+
+ byte[] bytes;
+
+ bytes = bOut.toByteArray();
+
+ if (!Arrays.areEqual(bytes, output))
+ {
+ fail("" + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes)));
+ }
+
+ //
+ // decryption pass
+ //
+ bIn = new ByteArrayInputStream(bytes);
+
+ cIn = new CipherInputStream(bIn, in);
+
+ try
+ {
+ DataInputStream dIn = new DataInputStream(cIn);
+
+ bytes = new byte[input.length];
+
+ for (int i = 0; i != input.length / 2; i++)
+ {
+ bytes[i] = (byte)dIn.read();
+ }
+ dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2);
+
+ dIn.close();
+ }
+ catch (Exception e)
+ {
+ fail("" + algorithm + " failed decryption - " + e.toString());
+ }
+
+ if (!Arrays.areEqual(bytes, input))
+ {
+ fail("" + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes)));
+ }
+ }
+
private boolean noIDEA()
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
index c8a43089..5457dabd 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
@@ -262,6 +262,7 @@ public class CertPathValidatorTest
CertPathValidator cpv = CertPathValidator.getInstance("PKIX","BC");
PKIXParameters param = new PKIXParameters(trust);
param.setRevocationEnabled(false);
+ param.setDate(new Date(0x156445410b4L)); // around 1st August 2016
CertPath cp = cf.generateCertPath(certchain);
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertTest.java
index 0661bd70..5e41d284 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CertTest.java
@@ -1,5 +1,6 @@
package org.bouncycastle.jce.provider.test;
+import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
@@ -21,7 +22,9 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.Set;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
@@ -1101,6 +1104,31 @@ public class CertTest
"AGfsxfTyldQDEOVzD/Uq8Xh4gIHuSqki9mRSjMR19MQtTKRmI9TRHIeTdIZ6l3P7" +
"jFfGJvTP0E9NYSolx+kM");
+ private final byte[] sha3Cert = Base64.decode(
+ "MIID8jCCAqagAwIBAgIICfBykpzUT+IwQQYJKoZIhvcNAQEKMDSgDzANBglg"
+ + "hkgBZQMEAggFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEg"
+ + "MCwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNB"
+ + "MTAeFw0xNjEwMTgxODQzMjhaFw0yNjEwMTgxODQzMjdaMCwxCzAJBgNVBAYT"
+ + "AkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNBMTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAK/pzm1RASDYDg3WBXyW3AnAESRF/+li"
+ + "qh0X8Y89m+JFJeOi1u89bOSPjsFfo5SbRSElyRXedh/d37KrONg39NEKIcC6"
+ + "iSuiNfXu0D6nlSzhrQzmvHIyfLnm8N2JtHDr/hZIprOcFO+lZTJIjjrOVe9y"
+ + "lFGgGDd/uQCEJk1Cmi5Ivi9odeiN3z8lVlGNeN9/Q5n47ijuYWr73z/FyyAK"
+ + "gAG3B5nhAYWs4ft0O3JWBc0QJZzShqsRjm3SNhAqMDnRoTq04PFgbDYizV8T"
+ + "ydz2kCne79TDwsY4MckYYaGoNcPoQXVS+9YjQjI72ktSlxiJxodL9WMFl+ED"
+ + "5ZLBRIRsDJECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MGoGCCsGAQUF"
+ + "BwEBBF4wXDAnBggrBgEFBQcwAoYbaHR0cDovL2V4YW1wbGUub3JnL1JDQTEu"
+ + "ZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vbG9jYWxob3N0OjgwODAvb2NzcC9y"
+ + "ZXNwb25kZXIxMB0GA1UdDgQWBBRTXKdJI3P1kveLlRxPvzUfDnC8JjAOBgNV"
+ + "HQ8BAf8EBAMCAQYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAggFAKEc"
+ + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEgA4IBAQCpSVaqOMKz"
+ + "6NT0+mivEhig9cKsglFhnWStKUtdhrG4HqOf6Qjny9Xvq1nE7x8e2xAoaZLd"
+ + "GMsNAWFCbwzoJrDL7Ct6itQ5ymxi2haN+Urc5UWJd/8C0R74OdP1uPCiljZ9"
+ + "DdjbNk/hS36UPYi+FT5r6Jr/1X/EqgL1MOUsSTEXdYlZH662zjbV4D9QSBzx"
+ + "ul9bYyWrqSZFKvKef4UQwUy8yXtChwiwp50mfJQBdVcIqPBYCgmLYclamjQx"
+ + "hlkk5VbZb4D/Cv4HxrdxpJfy/ewUZR7uHlzDx0/m4qjzNzWgq+sh3ZbveDrV"
+ + "wd/FDMFOxSIno9qgHtdfgXRwZJ+l07fF");
+
private final String ecPemCert =
"-----BEGIN CERTIFICATE-----\n" +
"MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\n" +
@@ -1587,6 +1615,74 @@ public class CertTest
}
}
+ private void pemFileTest()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC");
+
+ Collection<Certificate> certs1 = (Collection<Certificate>)certFact.generateCertificates(this.getClass().getResourceAsStream("cert_chain.txt"));
+
+ isTrue("certs wrong <cr><nl>", 2 == certs1.size());
+
+ BufferedInputStream in = new BufferedInputStream(this.getClass().getResourceAsStream("cert_chain.txt"));
+
+ Set certs2 = new HashSet();
+ while ((in.available() > 0))
+ {
+ Certificate c = certFact.generateCertificate(in);
+
+ // this isn't strictly correct with the way it's defined in the Java JavaDoc - need it for backward
+ // compatibility.
+ if (c != null)
+ {
+ certs2.add(c);
+ }
+ }
+
+ isTrue("certs size <cr><nl>", certs1.size() == certs2.size());
+
+ for (Iterator it = certs1.iterator(); it.hasNext();)
+ {
+ certs2.remove(it.next());
+ }
+
+ isTrue("collection not empty", certs2.isEmpty());
+ }
+
+ private void pemFileTestWithNl()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC");
+
+ Collection<Certificate> certs1 = (Collection<Certificate>)certFact.generateCertificates(this.getClass().getResourceAsStream("cert_chain_nl.txt"));
+
+ isTrue("certs wrong <nl>", 2 == certs1.size());
+
+ BufferedInputStream in = new BufferedInputStream(this.getClass().getResourceAsStream("cert_chain_nl.txt"));
+
+ Set certs2 = new HashSet();
+ while ((in.available() > 0))
+ {
+ Certificate c = certFact.generateCertificate(in);
+
+ // this isn't strictly correct with the way it's defined in the Java JavaDoc - need it for backward
+ // compatibility.
+ if (c != null)
+ {
+ certs2.add(c);
+ }
+ }
+
+ isTrue("certs size <nl>", certs1.size() == certs2.size());
+
+ for (Iterator it = certs1.iterator(); it.hasNext();)
+ {
+ certs2.remove(it.next());
+ }
+
+ isTrue("collection not empty", certs2.isEmpty());
+ }
+
public void performTest()
throws Exception
{
@@ -1630,9 +1726,13 @@ public class CertTest
}
}
+ checkSelfSignedCertificate(23, sha3Cert, "SHA3-256withRSAandMGF1");
+
checkCRL(1, crl1);
pemTest();
+ pemFileTest();
+ pemFileTestWithNl();
pkcs7Test();
rfc4491Test();
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java
index 28f99e57..6182dfe3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java
@@ -63,6 +63,15 @@ public class CipherStreamTest
+ "D44A7A7CDB84929F915420A8A3DC58BF"
+ "0F7ECB4B1F167BB1A5E6153FDAF4493D");
+ private static final byte[] CHA7539K = Hex.decode("8000000000000000000000000000000080000000000000000000000000000000");
+ private static final byte[] CHA7539IV = Hex.decode("000000000000000000000000");
+ private static final byte[] CHA7539IN = Hex.decode(
+ "00000000000000000000000000000000"
+ + "00000000000000000000000000000000"
+ + "00000000000000000000000000000000"
+ + "00000000000000000000000000000000");
+ private static final byte[] CHA7539OUT = Hex.decode("aef50e541e12a65dc21e90ebb4c03987971c540f78eb536df692ff89fc47561ed17eb23b63eb714c09d0c50af703e01485926c140e994b3edff9df635a91d268");
+
private static final byte[] HCIN = new byte[64];
private static final byte[] HCIV = new byte[32];
@@ -259,7 +268,7 @@ public class CipherStreamTest
(byte)137, (byte)138, (byte)140, (byte)143 };
byte[] keyBytes;
- if (name.equals("HC256") || name.equals("XSalsa20"))
+ if (name.equals("HC256") || name.equals("XSalsa20") || name.equals("ChaCha7539"))
{
keyBytes = key256;
}
@@ -377,6 +386,9 @@ public class CipherStreamTest
runTest("ChaCha");
testException("ChaCha");
testAlgorithm("ChaCha", CHAK, CHAIV, CHAIN, CHAOUT);
+ runTest("ChaCha7539");
+ testException("ChaCha7539");
+ testAlgorithm("ChaCha7539", CHA7539K, CHA7539IV, CHA7539IN, CHA7539OUT);
runTest("HC128");
testException("HC128");
testAlgorithm("HC128", HCK128A, HCIV, HCIN, HC128A);
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java
index 2201c8a6..8f4cf012 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/CipherStreamTest2.java
@@ -1,10 +1,15 @@
package org.bouncycastle.jce.provider.test;
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.security.Key;
import java.security.Security;
-import javax.crypto.*;
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.crypto.io.InvalidCipherTextIOException;
@@ -499,6 +504,7 @@ public class CipherStreamTest2
"SALSA20",
"XSalsa20",
"ChaCha",
+ "ChaCha7539",
"Grainv1",
"Grain128",
"HC128",
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHIESTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHIESTest.java
index f081d80b..a21bbc2e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHIESTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHIESTest.java
@@ -1,11 +1,13 @@
package org.bouncycastle.jce.provider.test;
import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
+import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
@@ -18,9 +20,10 @@ import org.bouncycastle.crypto.engines.IESEngine;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.asymmetric.dh.IESCipher;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.IESParameterSpec;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -65,17 +68,18 @@ public class DHIESTest
// Testing DHIES with default prime in streaming mode
KeyPairGenerator g = KeyPairGenerator.getInstance("DH", "BC");
+ KeyPairGenerator g512 = KeyPairGenerator.getInstance("DH", "BC");
g.initialize(param);
doTest("DHIES with default", g, "DHIES", params);
// Testing DHIES with 512-bit prime in streaming mode
- g.initialize(512, new SecureRandom());
- doTest("DHIES with 512-bit", g, "DHIES", params);
+ g512.initialize(512, new SecureRandom());
+ doTest("DHIES with 512-bit", g512, "DHIES", params);
// Testing ECIES with 1024-bit prime in streaming mode
- g.initialize(1024, new SecureRandom());
+ g.initialize(param, new SecureRandom());
doTest("DHIES with 1024-bit", g, "DHIES", params);
c1 = new IESCipher(new IESEngine(new DHBasicAgreement(),
@@ -88,43 +92,79 @@ public class DHIESTest
new HMac(new SHA1Digest()),
new PaddedBufferedBlockCipher(new DESEngine())));
- params = new IESParameterSpec(derivation, encoding, 128, 192);
+ params = new IESParameterSpec(derivation, encoding, 128, 192, Hex.decode("0001020304050607"));
// Testing DHIES with default prime using DESEDE
g = KeyPairGenerator.getInstance("DH", "BC");
- doTest("DHIESwithDES default", g, "DHIESwithDESEDE", params);
+ doTest("DHIESwithDES default", g, "DHIESwithDESEDE-CBC", params);
// Testing DHIES with 512-bit prime using DESEDE
- g.initialize(512, new SecureRandom());
- doTest("DHIESwithDES 512-bit", g, "DHIESwithDESEDE", params);
+ doTest("DHIESwithDES 512-bit", g512, "DHIESwithDESEDE-CBC", params);
// Testing DHIES with 1024-bit prime using DESEDE
- g.initialize(1024, new SecureRandom());
- doTest("DHIESwithDES 1024-bit", g, "DHIESwithDESEDE", params);
+ g.initialize(param, new SecureRandom());
+ doTest("DHIESwithDES 1024-bit", g, "DHIESwithDESEDE-CBC", params);
g = KeyPairGenerator.getInstance("DH", "BC");
g.initialize(param);
- c1 = new IESCipher.IESwithAES();
- c2 = new IESCipher.IESwithAES();
- params = new IESParameterSpec(derivation, encoding, 128, 128);
-
- // Testing DHIES with default curve using AES
- doTest("DHIESwithAES default", g, "DHIESwithAES", params);
+ c1 = new IESCipher.IESwithAESCBC();
+ c2 = new IESCipher.IESwithAESCBC();
+ params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("00010203040506070001020304050607"));
- // Testing DHIES with 512-bit curve using AES
- g.initialize(512, new SecureRandom());
- doTest("DHIESwithAES 512-bit", g, "DHIESwithAES", params);
+ // Testing DHIES with default prime using AES
+ doTest("DHIESwithAES default", g, "DHIESwithAES-CBC", params);
- // Testing DHIES with 1024-bit curve using AES
- g.initialize(1024, new SecureRandom());
- doTest("DHIESwithAES 1024-bit", g, "DHIESwithAES", params);
+ // Testing DHIES with 512-bit prime using AES
+ doTest("DHIESwithAES 512-bit", g512, "DHIESwithAES-CBC", params);
+ // Testing DHIES with 1024-bit prime using AES
+ g.initialize(param, new SecureRandom());
+ doTest("DHIESwithAES 1024-bit", g, "DHIESwithAES-CBC", params);
+
+ KeyPair keyPair = g.generateKeyPair();
+ DHPublicKey pub = (DHPublicKey)keyPair.getPublic();
+ DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate();
+
+ Cipher c = Cipher.getInstance("DHIESwithAES-CBC", "BC");
+
+ try
+ {
+ c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null));
+
+ fail("no exception");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
+
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, priv);
+
+ fail("no exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
+
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null));
+
+ fail("no exception");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
}
public void doTest(
- String testname,
- KeyPairGenerator g,
+ String testname,
+ KeyPairGenerator g,
String cipher,
IESParameterSpec p)
throws Exception
@@ -139,22 +179,23 @@ public class DHIESTest
KeyPair keyPair = g.generateKeyPair();
DHPublicKey pub = (DHPublicKey)keyPair.getPublic();
DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate();
-
- // Testing with null parameters and DHAES mode off
+ // Testing with default parameters and DHAES mode off
c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom());
- c2.init(Cipher.DECRYPT_MODE, priv, new SecureRandom());
+ c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters());
+
+ isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV()));
+
out1 = c1.doFinal(message, 0, message.length);
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
{
- fail(testname + " test failed with null parameters, DHAES mode false.");
+ fail(testname + " test failed with default parameters, DHAES mode false.");
}
-
// Testing with given parameters and DHAES mode off
c1.init(Cipher.ENCRYPT_MODE, pub, p, new SecureRandom());
- c2.init(Cipher.DECRYPT_MODE, priv, p, new SecureRandom());
+ c2.init(Cipher.DECRYPT_MODE, priv, p);
out1 = c1.doFinal(message, 0, message.length);
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
@@ -164,7 +205,7 @@ public class DHIESTest
c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC");
c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC");
c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom());
- c2.init(Cipher.DECRYPT_MODE, priv, new SecureRandom());
+ c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters(), new SecureRandom());
out1 = c1.doFinal(message, 0, message.length);
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
@@ -182,6 +223,27 @@ public class DHIESTest
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
fail(testname + " test failed with non-null parameters, DHAES mode true.");
+
+ //
+ // corrupted data test
+ //
+ byte[] tmp = new byte[out1.length];
+ for (int i = 0; i != out1.length; i++)
+ {
+ System.arraycopy(out1, 0, tmp, 0, tmp.length);
+ tmp[i] = (byte)~tmp[i];
+
+ try
+ {
+ c2.doFinal(tmp, 0, tmp.length);
+
+ fail("decrypted corrupted data");
+ }
+ catch (BadPaddingException e)
+ {
+ isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage()));
+ }
+ }
}
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHTest.java
index ef4c0454..4be5a104 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DHTest.java
@@ -7,16 +7,21 @@ import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@@ -52,51 +57,51 @@ public class DHTest
private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);
- private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
- private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
+ private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
+ private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
// public key with mismatched oid/parameters
private byte[] oldPubEnc = Base64.decode(
"MIIBnzCCARQGByqGSM4+AgEwggEHAoGBAPxSrN417g43VAM9sZRf1dt6AocAf7D6" +
- "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" +
- "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" +
- "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" +
- "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" +
- "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" +
- "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" +
- "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" +
- "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU=");
+ "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" +
+ "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" +
+ "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" +
+ "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" +
+ "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" +
+ "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" +
+ "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" +
+ "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU=");
// bogus key with full PKCS parameter set
private byte[] oldFullParams = Base64.decode(
"MIIBIzCCARgGByqGSM4+AgEwggELAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E" +
- "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" +
- "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" +
- "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" +
- "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" +
- "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" +
- "AwUAAgIH0A==");
+ "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" +
+ "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" +
+ "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" +
+ "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" +
+ "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" +
+ "AwUAAgIH0A==");
private byte[] samplePubEnc = Base64.decode(
- "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" +
- "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" +
- "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" +
- "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" +
- "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" +
- "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" +
- "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" +
- "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" +
- "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB");
+ "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" +
+ "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" +
+ "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" +
+ "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" +
+ "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" +
+ "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" +
+ "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" +
+ "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" +
+ "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB");
private byte[] samplePrivEnc = Base64.decode(
- "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" +
- "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" +
- "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" +
- "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" +
- "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" +
- "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" +
- "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" +
- "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q=");
+ "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" +
+ "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" +
+ "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" +
+ "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" +
+ "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" +
+ "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" +
+ "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" +
+ "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q=");
public String getName()
{
@@ -104,14 +109,14 @@ public class DHTest
}
private void testGP(
- String algName,
- int size,
- int privateValueSize,
- BigInteger g,
- BigInteger p)
+ String algName,
+ int size,
+ int privateValueSize,
+ BigInteger g,
+ BigInteger p)
throws Exception
{
- DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
+ DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algName, "BC");
@@ -124,11 +129,11 @@ public class DHTest
//
// public key encoding test
//
- byte[] pubEnc = aKeyPair.getPublic().getEncoded();
- KeyFactory keyFac = KeyFactory.getInstance(algName, "BC");
- X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
- DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509);
- DHParameterSpec spec = pubKey.getParams();
+ byte[] pubEnc = aKeyPair.getPublic().getEncoded();
+ KeyFactory keyFac = KeyFactory.getInstance(algName, "BC");
+ X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
+ DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509);
+ DHParameterSpec spec = pubKey.getParams();
if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP()))
{
@@ -169,9 +174,9 @@ public class DHTest
//
// private key encoding test
//
- byte[] privEnc = aKeyPair.getPrivate().getEncoded();
+ byte[] privEnc = aKeyPair.getPrivate().getEncoded();
PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
- DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8);
+ DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8);
spec = privKey.getParams();
@@ -268,7 +273,7 @@ public class DHTest
}
private void testTwoParty(String algName, int size, int privateValueSize, KeyPairGenerator keyGen)
- throws Exception
+ throws Exception
{
testTwoParty(algName, size, privateValueSize, keyGen.generateKeyPair(), keyGen.generateKeyPair());
}
@@ -312,13 +317,13 @@ public class DHTest
}
private void testExplicitWrapping(
- int size,
- int privateValueSize,
- BigInteger g,
- BigInteger p)
+ int size,
+ int privateValueSize,
+ BigInteger g,
+ BigInteger p)
throws Exception
{
- DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
+ DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
@@ -354,7 +359,7 @@ public class DHTest
SecretKey k1 = aKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId());
SecretKey k2 = bKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId());
-
+
// TODO Compare k1 and k2?
}
@@ -386,7 +391,7 @@ public class DHTest
}
private void testRandom(
- int size)
+ int size)
throws Exception
{
AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DH", "BC");
@@ -412,14 +417,14 @@ public class DHTest
}
private void testDefault(
- int privateValueSize,
- BigInteger g,
- BigInteger p)
+ int privateValueSize,
+ BigInteger g,
+ BigInteger p)
throws Exception
{
- DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
- String algName = "DH";
- int size = p.bitLength();
+ DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize);
+ String algName = "DH";
+ int size = p.bitLength();
new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, dhParams);
@@ -436,11 +441,11 @@ public class DHTest
//
// public key encoding test
//
- byte[] pubEnc = aKeyPair.getPublic().getEncoded();
- KeyFactory keyFac = KeyFactory.getInstance(algName, "BC");
- X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
- DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509);
- DHParameterSpec spec = pubKey.getParams();
+ byte[] pubEnc = aKeyPair.getPublic().getEncoded();
+ KeyFactory keyFac = KeyFactory.getInstance(algName, "BC");
+ X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
+ DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509);
+ DHParameterSpec spec = pubKey.getParams();
if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP()))
{
@@ -455,13 +460,13 @@ public class DHTest
//
// public key serialisation test
//
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ObjectOutputStream oOut = new ObjectOutputStream(bOut);
oOut.writeObject(aKeyPair.getPublic());
- ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
- ObjectInputStream oIn = new ObjectInputStream(bIn);
+ ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
+ ObjectInputStream oIn = new ObjectInputStream(bIn);
pubKey = (DHPublicKey)oIn.readObject();
spec = pubKey.getParams();
@@ -479,9 +484,9 @@ public class DHTest
//
// private key encoding test
//
- byte[] privEnc = aKeyPair.getPrivate().getEncoded();
+ byte[] privEnc = aKeyPair.getPrivate().getEncoded();
PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
- DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8);
+ DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8);
spec = privKey.getParams();
@@ -573,7 +578,7 @@ public class DHTest
private void testECDH(String algorithm, String curveName, String cipher, int keyLen)
throws Exception
{
- ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec("secp521r1");
+ ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC");
g.initialize(parameterSpec);
@@ -603,7 +608,7 @@ public class DHTest
bKeyAgree.doPhase(aKeyPair.getPublic(), true);
SecretKey k1 = aKeyAgree.generateSecret(cipher);
- SecretKey k2 = bKeyAgree.generateSecret(cipher);
+ SecretKey k2 = bKeyAgree.generateSecret(cipher + "[" + keyLen + "]"); // explicit key-len
if (!k1.equals(k2))
{
@@ -619,18 +624,18 @@ public class DHTest
private void testECDH(String algorithm)
throws Exception
{
- KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC");
+ KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC");
EllipticCurve curve = new EllipticCurve(
- new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
- new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
- new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+ new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
ECParameterSpec ecSpec = new ECParameterSpec(
- curve,
- ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
- new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
- 1); // h
+ curve,
+ ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
+ 1); // h
g.initialize(ecSpec, new SecureRandom());
@@ -658,8 +663,8 @@ public class DHTest
aKeyAgree.doPhase(bKeyPair.getPublic(), true);
bKeyAgree.doPhase(aKeyPair.getPublic(), true);
- BigInteger k1 = new BigInteger(aKeyAgree.generateSecret());
- BigInteger k2 = new BigInteger(bKeyAgree.generateSecret());
+ BigInteger k1 = new BigInteger(aKeyAgree.generateSecret());
+ BigInteger k2 = new BigInteger(bKeyAgree.generateSecret());
if (!k1.equals(k2))
{
@@ -669,10 +674,10 @@ public class DHTest
//
// public key encoding test
//
- byte[] pubEnc = aKeyPair.getPublic().getEncoded();
- KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC");
- X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
- ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
+ byte[] pubEnc = aKeyPair.getPublic().getEncoded();
+ KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC");
+ X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
+ ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
if (!pubKey.getW().equals(((ECPublicKey)aKeyPair.getPublic()).getW()))
{
@@ -689,9 +694,9 @@ public class DHTest
//
// private key encoding test
//
- byte[] privEnc = aKeyPair.getPrivate().getEncoded();
+ byte[] privEnc = aKeyPair.getPrivate().getEncoded();
PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
- ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
+ ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
if (!privKey.getS().equals(((ECPrivateKey)aKeyPair.getPrivate()).getS()))
{
@@ -705,6 +710,7 @@ public class DHTest
}
private void testExceptions()
+ throws Exception
{
try
{
@@ -720,12 +726,39 @@ public class DHTest
{
fail("Unexpected exception: " + e, e);
}
+
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
+
+ keyGen.initialize(256);
+
+ KeyPair kp = keyGen.generateKeyPair();
+ KeyAgreement agreement = KeyAgreement.getInstance("ECDH", "BC");
+
+ agreement.init(kp.getPrivate());
+ try
+ {
+ ECPoint fakePubPoint = new ECPoint(new BigInteger("12345"), new BigInteger("23457"));
+ ECPublicKeySpec fakePubSpec = new ECPublicKeySpec(fakePubPoint, ((ECPublicKey)kp.getPublic()).getParams());
+ KeyFactory kf = KeyFactory.getInstance("EC", "BC");
+ PublicKey fakePub = kf.generatePublic(fakePubSpec);
+ agreement.doPhase(fakePub, true);
+
+ fail("no exception on dud point");
+ }
+ catch (java.security.spec.InvalidKeySpecException e)
+ {
+ isTrue("wrong message", "invalid KeySpec: point not on curve".equals(e.getMessage()));
+ }
+ catch (java.security.InvalidKeyException e)
+ {
+ isTrue("wrong message", "calculation failed: Invalid point".equals(e.getMessage()));
+ }
}
private void testDESAndDESede(BigInteger g, BigInteger p)
throws Exception
{
- DHParameterSpec dhParams = new DHParameterSpec(p, g, 256);
+ DHParameterSpec dhParams = new DHParameterSpec(p, g, 256);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
@@ -791,13 +824,13 @@ public class DHTest
DHPrivateKeySpec aPrivSpec = new DHPrivateKeySpec(
new BigInteger("30a6ea4e2240a42867ad98bd3adbfd5b81aba48bd930f20a595983d807566f7cba4e766951efef2c6c0c1be3823f63d66e12c2a091d5ff3bbeb1ea6e335d072d", 16), p, g);
DHPublicKeySpec aPubSpec = new DHPublicKeySpec(
- new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g);
+ new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g);
DHPrivateKeySpec bPrivSpec = new DHPrivateKeySpec(
- new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g);
+ new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g);
DHPublicKeySpec bPubSpec = new DHPublicKeySpec(
- new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g);
+ new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g);
KeyFactory kFact = KeyFactory.getInstance("DH", "BC");
@@ -817,7 +850,7 @@ public class DHTest
private void testEnc()
throws Exception
{
- KeyFactory kFact = KeyFactory.getInstance("DH", "BC");
+ KeyFactory kFact = KeyFactory.getInstance("DH", "BC");
Key k = kFact.generatePrivate(new PKCS8EncodedKeySpec(samplePrivEnc));
@@ -858,9 +891,9 @@ public class DHTest
384);
DHParameterSpec dhSpec768 = new DHParameterSpec(
- new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16),
- new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16),
- 384);
+ new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16),
+ new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16),
+ 384);
DHParameterSpec dhSpec1024 = new DHParameterSpec(
new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16),
@@ -879,7 +912,7 @@ public class DHTest
fail("config found when none expected");
}
- prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 });
+ prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024});
if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512)))
{
@@ -920,7 +953,7 @@ public class DHTest
fail("config found when none expected");
}
- prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 });
+ prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024});
if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512)))
{
@@ -950,6 +983,109 @@ public class DHTest
}
}
+ static final String MESSAGE = "Hello";
+
+ static final String PROVIDER_NAME = "BC";
+ static final SecureRandom rand = new SecureRandom();
+
+ public void setUp()
+ {
+ // Add BouncyCastle for testing.
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
+ System.out.println("WARNING: Using BouncyCastleProvider");
+ }
+
+ public DHParameterSpec ike2048()
+ {
+ final BigInteger p = new BigInteger(
+ "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+ + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+ + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+ + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+ + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+ + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b"
+ + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718"
+ + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff", 16);
+ final BigInteger g = new BigInteger("2");
+ return new DHParameterSpec(p, g);
+ }
+
+ /**
+ * Tests whether a provider accepts invalid public keys that result in predictable shared secrets.
+ * This test is based on RFC 2785, Section 4 and NIST SP 800-56A,
+ * If an attacker can modify both public keys in an ephemeral-ephemeral key agreement scheme then
+ * it may be possible to coerce both parties into computing the same predictable shared key.
+ * <p/>
+ * Note: the test is quite whimsical. If the prime p is not a safe prime then the provider itself
+ * cannot prevent all small-subgroup attacks because of the missing parameter q in the
+ * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones
+ * proposed in RFC 2785.
+ */
+ private void testSubgroupConfinement()
+ throws Exception
+ {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
+ DHParameterSpec params = ike2048();
+ final BigInteger p = params.getP();
+ final BigInteger g = params.getG();
+ keyGen.initialize(params);
+ PrivateKey priv = keyGen.generateKeyPair().getPrivate();
+ KeyAgreement ka = KeyAgreement.getInstance("DH", "BC");
+ BigInteger[] weakPublicKeys = {
+ BigInteger.ZERO, BigInteger.ONE, p.subtract(BigInteger.ONE), p,
+ p.add(BigInteger.ONE), BigInteger.ONE.negate()};
+ for (final BigInteger weakKey : weakPublicKeys)
+ {
+ DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g);
+ KeyFactory kf = KeyFactory.getInstance("DH", "BC");
+ try
+ {
+ kf.generatePublic(weakSpec);
+ fail("Generated weak public key");
+ }
+ catch (GeneralSecurityException ex)
+ {
+ isTrue("wrong message (generate)", "invalid DH public key".equals(ex.getMessage()));
+ }
+ ka.init(priv);
+ try
+ {
+ ka.doPhase(new DHPublicKey()
+ {
+ public BigInteger getY()
+ {
+ return weakKey;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return new DHParameterSpec(p, g);
+ }
+
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return new byte[0];
+ }
+ }, true);
+ fail("Generated secrets with weak public key");
+ }
+ catch (GeneralSecurityException ex)
+ {
+ isTrue("wrong message (doPhase)", "Invalid DH PublicKey".equals(ex.getMessage()));
+ }
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -983,10 +1119,11 @@ public class DHTest
testInitialise();
testSmallSecret();
testConfig();
+ testSubgroupConfinement();
}
public static void main(
- String[] args)
+ String[] args)
{
Security.addProvider(new BouncyCastleProvider());
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSATest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSATest.java
index 0dd9981a..6d7b8581 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSATest.java
@@ -12,15 +12,21 @@ import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
+import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@@ -30,10 +36,16 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.signers.DSASigner;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -48,6 +60,8 @@ import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
+import org.bouncycastle.util.test.TestRandomData;
public class DSATest
extends SimpleTest
@@ -56,7 +70,112 @@ public class DSATest
byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 });
-
+
+ // DSA modified signatures, courtesy of the Google security team
+ static final DSAPrivateKeySpec PRIVATE_KEY = new DSAPrivateKeySpec(
+ // x
+ new BigInteger(
+ "15382583218386677486843706921635237927801862255437148328980464126979"),
+ // p
+ new BigInteger(
+ "181118486631420055711787706248812146965913392568235070235446058914"
+ + "1170708161715231951918020125044061516370042605439640379530343556"
+ + "4101919053459832890139496933938670005799610981765220283775567361"
+ + "4836626483403394052203488713085936276470766894079318754834062443"
+ + "1033792580942743268186462355159813630244169054658542719322425431"
+ + "4088256212718983105131138772434658820375111735710449331518776858"
+ + "7867938758654181244292694091187568128410190746310049564097068770"
+ + "8161261634790060655580211122402292101772553741704724263582994973"
+ + "9109274666495826205002104010355456981211025738812433088757102520"
+ + "562459649777989718122219159982614304359"),
+ // q
+ new BigInteger(
+ "19689526866605154788513693571065914024068069442724893395618704484701"),
+ // g
+ new BigInteger(
+ "2859278237642201956931085611015389087970918161297522023542900348"
+ + "0877180630984239764282523693409675060100542360520959501692726128"
+ + "3149190229583566074777557293475747419473934711587072321756053067"
+ + "2532404847508798651915566434553729839971841903983916294692452760"
+ + "2490198571084091890169933809199002313226100830607842692992570749"
+ + "0504363602970812128803790973955960534785317485341020833424202774"
+ + "0275688698461842637641566056165699733710043802697192696426360843"
+ + "1736206792141319514001488556117408586108219135730880594044593648"
+ + "9237302749293603778933701187571075920849848690861126195402696457"
+ + "4111219599568903257472567764789616958430"));
+
+ static final DSAPublicKeySpec PUBLIC_KEY = new DSAPublicKeySpec(
+ new BigInteger(
+ "3846308446317351758462473207111709291533523711306097971550086650"
+ + "2577333637930103311673872185522385807498738696446063139653693222"
+ + "3528823234976869516765207838304932337200968476150071617737755913"
+ + "3181601169463467065599372409821150709457431511200322947508290005"
+ + "1780020974429072640276810306302799924668893998032630777409440831"
+ + "4314588994475223696460940116068336991199969153649625334724122468"
+ + "7497038281983541563359385775312520539189474547346202842754393945"
+ + "8755803223951078082197762886933401284142487322057236814878262166"
+ + "5072306622943221607031324846468109901964841479558565694763440972"
+ + "5447389416166053148132419345627682740529"),
+ PRIVATE_KEY.getP(),
+ PRIVATE_KEY.getQ(),
+ PRIVATE_KEY.getG());
+
+ // The following test vectors check for signature malleability and bugs. That means the test
+ // vectors are derived from a valid signature by modifying the ASN encoding. A correct
+ // implementation of DSA should only accept correct DER encoding and properly handle the others.
+ // Allowing alternative BER encodings is in many cases benign. An example where this kind of
+ // signature malleability was a problem: https://en.bitcoin.it/wiki/Transaction_Malleability
+ static final String[] MODIFIED_SIGNATURES = {
+ "303e02811c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e"
+ + "f41dd424a4e1c8f16967cf3365813fe8786236",
+ "303f0282001c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f"
+ + "9ef41dd424a4e1c8f16967cf3365813fe8786236",
+ "303e021d001e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e"
+ + "f41dd424a4e1c8f16967cf3365813fe8786236",
+ "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd02811d00ade65988d237d30f9e"
+ + "f41dd424a4e1c8f16967cf3365813fe8786236",
+ "303f021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd0282001d00ade65988d237d30f"
+ + "9ef41dd424a4e1c8f16967cf3365813fe8786236",
+ "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021e0000ade65988d237d30f9e"
+ + "f41dd424a4e1c8f16967cf3365813fe8786236",
+ "30813d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e"
+ + "f41dd424a4e1c8f16967cf3365813fe8786236",
+ "3082003d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f"
+ + "9ef41dd424a4e1c8f16967cf3365813fe8786236",
+ "303d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9ef4"
+ + "1dd424a4e1c8f16967cf3365813fe87862360000",
+ "3040021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca8021d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3040100",
+ "303e021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca802811d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3"
+ };
+
+ private void testModified()
+ throws Exception
+ {
+ KeyFactory kFact = KeyFactory.getInstance("DSA", "BC");
+ PublicKey pubKey = kFact.generatePublic(PUBLIC_KEY);
+ Signature sig = Signature.getInstance("DSA", "BC");
+
+ for (int i = 0; i != MODIFIED_SIGNATURES.length; i++)
+ {
+ sig.initVerify(pubKey);
+
+ sig.update(Strings.toByteArray("Hello"));
+
+ boolean failed;
+
+ try
+ {
+ failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i]));
+ }
+ catch (SignatureException e)
+ {
+ failed = true;
+ }
+
+ isTrue("sig verified when shouldn't", failed);
+ }
+ }
+
private void testCompat()
throws Exception
{
@@ -149,6 +268,66 @@ public class DSATest
checkPrivateKey(k2, sKey);
}
+ private void testNullParameters()
+ throws Exception
+ {
+ KeyFactory f = KeyFactory.getInstance("DSA", "BC");
+ X509EncodedKeySpec x509s = new X509EncodedKeySpec(new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(10001)).getEncoded());
+
+ DSAPublicKey key1 = (DSAPublicKey)f.generatePublic(x509s);
+ DSAPublicKey key2 = (DSAPublicKey)f.generatePublic(x509s);
+
+ isTrue("parameters not absent", key1.getParams() == null && key2.getParams() == null);
+ isTrue("hashCode mismatch", key1.hashCode() == key2.hashCode());
+ isTrue("not equal", key1.equals(key2));
+ isTrue("encoding mismatch", Arrays.areEqual(x509s.getEncoded(), key1.getEncoded()));
+ }
+
+ private void testValidate()
+ throws Exception
+ {
+ DSAParameterSpec dsaParams = new DSAParameterSpec(
+ new BigInteger(
+ "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+ "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+ "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+ "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+ "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+ "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+ "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+ "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+ "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+ "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+ "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16),
+ new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16),
+ new BigInteger(
+ "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+ "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+ "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+ "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+ "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+ "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+ "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+ "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+ "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+ "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+ "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)
+ );
+
+ KeyFactory f = KeyFactory.getInstance("DSA", "BC");
+
+ try
+ {
+ f.generatePublic(new DSAPublicKeySpec(BigInteger.valueOf(1), dsaParams.getP(), dsaParams.getG(), dsaParams.getQ()));
+
+ fail("no exception");
+ }
+ catch (Exception e)
+ {
+ isTrue("mismatch", "invalid KeySpec: y value does not appear to be in correct group".equals(e.getMessage()));
+ }
+ }
+
private void testNONEwithDSA()
throws Exception
{
@@ -271,7 +450,7 @@ public class DSATest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve curve = new ECCurve.Fp(
new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
@@ -374,12 +553,191 @@ public class DSATest
checkMessage(sgr, sKey, vKey, message, sig);
}
+ private void testECDSAP256sha3(ASN1ObjectIdentifier sigOid, int size, BigInteger s)
+ throws Exception
+ {
+ X9ECParameters p = NISTNamedCurves.getByName("P-256");
+ KeyFactory ecKeyFact = KeyFactory.getInstance("EC", "BC");
+
+ ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH());
+
+ ECCurve curve = p.getCurve();
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ p.getG(), // G
+ p.getN()); // n
+
+ ECPrivateKeySpec priKey = new ECPrivateKeySpec(
+ new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d
+ spec);
+
+ ECPublicKeySpec pubKey = new ECPublicKeySpec(
+ params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q
+ spec);
+
+ doEcDsaTest("SHA3-" + size + "withECDSA", s, ecKeyFact, pubKey, priKey);
+ doEcDsaTest(sigOid.getId(), s, ecKeyFact, pubKey, priKey);
+ }
+
+ private void doEcDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, ECPublicKeySpec pubKey, ECPrivateKeySpec priKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException
+ {
+ SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335")));
+
+ byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
+
+ Signature dsa = Signature.getInstance(sigName, "BC");
+
+ dsa.initSign(ecKeyFact.generatePrivate(priKey), k);
+
+ dsa.update(M, 0, M.length);
+
+ byte[] encSig = dsa.sign();
+
+ ASN1Sequence sig = ASN1Sequence.getInstance(encSig);
+
+ BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384");
+
+ BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue();
+ if (!r.equals(sigR))
+ {
+ fail("r component wrong." + Strings.lineSeparator()
+ + " expecting: " + r.toString(16) + Strings.lineSeparator()
+ + " got : " + sigR.toString(16));
+ }
+
+ BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue();
+ if (!s.equals(sigS))
+ {
+ fail("s component wrong." + Strings.lineSeparator()
+ + " expecting: " + s.toString(16) + Strings.lineSeparator()
+ + " got : " + sigS.toString(16));
+ }
+
+ // Verify the signature
+ dsa.initVerify(ecKeyFact.generatePublic(pubKey));
+
+ dsa.update(M, 0, M.length);
+
+ if (!dsa.verify(encSig))
+ {
+ fail("signature fails");
+ }
+ }
+
+ private void testDSAsha3(ASN1ObjectIdentifier sigOid, int size, BigInteger s)
+ throws Exception
+ {
+ DSAParameterSpec dsaParams = new DSAParameterSpec(
+ new BigInteger(
+ "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+ "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+ "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+ "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+ "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+ "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+ "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+ "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+ "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+ "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+ "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16),
+ new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16),
+ new BigInteger(
+ "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+ "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+ "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+ "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+ "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+ "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+ "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+ "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+ "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+ "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+ "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)
+ );
+
+ BigInteger x = new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16);
+
+ BigInteger y = new BigInteger(
+ "2828003D7C747199143C370FDD07A286" +
+ "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+ "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+ "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+ "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+ "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+ "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+ "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+ "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+ "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+ "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16);
+
+ DSAPrivateKeySpec priKey = new DSAPrivateKeySpec(
+ x, dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+
+ DSAPublicKeySpec pubKey = new DSAPublicKeySpec(
+ y, dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+
+ KeyFactory dsaKeyFact = KeyFactory.getInstance("DSA", "BC");
+
+ doDsaTest("SHA3-" + size + "withDSA", s, dsaKeyFact, pubKey, priKey);
+ doDsaTest(sigOid.getId(), s, dsaKeyFact, pubKey, priKey);
+ }
+
+ private void doDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, DSAPublicKeySpec pubKey, DSAPrivateKeySpec priKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException
+ {
+ SecureRandom k = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))),
+ new FixedSecureRandom.Data(Hex.decode("01020304")) });
+
+ byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
+
+ Signature dsa = Signature.getInstance(sigName, "BC");
+
+ dsa.initSign(ecKeyFact.generatePrivate(priKey), k);
+
+ dsa.update(M, 0, M.length);
+
+ byte[] encSig = dsa.sign();
+
+ ASN1Sequence sig = ASN1Sequence.getInstance(encSig);
+
+ BigInteger r = new BigInteger("4864074fe30e6601268ee663440e4d9b703f62673419864e91e9edb0338ce510", 16);
+
+ BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue();
+ if (!r.equals(sigR))
+ {
+ fail("r component wrong." + Strings.lineSeparator()
+ + " expecting: " + r.toString(16) + Strings.lineSeparator()
+ + " got : " + sigR.toString(16));
+ }
+
+ BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue();
+ if (!s.equals(sigS))
+ {
+ fail("s component wrong." + Strings.lineSeparator()
+ + " expecting: " + s.toString(16) + Strings.lineSeparator()
+ + " got : " + sigS.toString(16));
+ }
+
+ // Verify the signature
+ dsa.initVerify(ecKeyFact.generatePublic(pubKey));
+
+ dsa.update(M, 0, M.length);
+
+ if (!dsa.verify(encSig))
+ {
+ fail("signature fails");
+ }
+ }
+
private void checkMessage(Signature sgr, PrivateKey sKey, PublicKey vKey, byte[] message, byte[] sig)
throws InvalidKeyException, SignatureException
{
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
sgr.initSign(sKey, k);
@@ -415,7 +773,7 @@ public class DSATest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve curve = new ECCurve.F2m(
239, // m
@@ -480,7 +838,7 @@ public class DSATest
{
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve curve = new ECCurve.F2m(
239, // m
@@ -875,7 +1233,7 @@ public class DSATest
}
KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC");
- g.initialize(dsaP, new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")));
+ g.initialize(dsaP, new TestRandomBigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")));
KeyPair p = g.generateKeyPair();
DSAPrivateKey sKey = (DSAPrivateKey)p.getPrivate();
@@ -937,11 +1295,62 @@ public class DSATest
}
}
+ private void testKeyGeneration(int keysize)
+ throws Exception
+ {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA", "BC");
+ generator.initialize(keysize);
+ KeyPair keyPair = generator.generateKeyPair();
+ DSAPrivateKey priv = (DSAPrivateKey)keyPair.getPrivate();
+ DSAParams params = priv.getParams();
+ isTrue("keysize mismatch", keysize == params.getP().bitLength());
+ // The NIST standard does not fully specify the size of q that
+ // must be used for a given key size. Hence there are differences.
+ // For example if keysize = 2048, then OpenSSL uses 256 bit q's by default,
+ // but the SUN provider uses 224 bits. Both are acceptable sizes.
+ // The tests below simply asserts that the size of q does not decrease the
+ // overall security of the DSA.
+ int qsize = params.getQ().bitLength();
+ switch (keysize)
+ {
+ case 1024:
+ isTrue("Invalid qsize for 1024 bit key:" + qsize, qsize >= 160);
+ break;
+ case 2048:
+ isTrue("Invalid qsize for 2048 bit key:" + qsize, qsize >= 224);
+ break;
+ case 3072:
+ isTrue("Invalid qsize for 3072 bit key:" + qsize, qsize >= 256);
+ break;
+ default:
+ fail("Invalid key size:" + keysize);
+ }
+ // Check the length of the private key.
+ // For example GPG4Browsers or the KJUR library derived from it use
+ // q.bitCount() instead of q.bitLength() to determine the size of the private key
+ // and hence would generate keys that are much too small.
+ isTrue("privkey error", priv.getX().bitLength() >= qsize - 32);
+ }
+
+ private void testKeyGenerationAll()
+ throws Exception
+ {
+ testKeyGeneration(1024);
+ testKeyGeneration(2048);
+ testKeyGeneration(3072);
+ }
+
public void performTest()
throws Exception
{
testCompat();
testNONEwithDSA();
+
+ testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_224, 224, new BigInteger("613202af2a7f77e02b11b5c3a5311cf6b412192bc0032aac3ec127faebfc6bd0", 16));
+ testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_256, 256, new BigInteger("2450755c5e15a691b121bc833b97864e34a61ee025ecec89289c949c1858091e", 16));
+ testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_384, 384, new BigInteger("7aad97c0b71bb1e1a6483b6948a03bbe952e4780b0cee699a11731f90d84ddd1", 16));
+ testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_512, 512, new BigInteger("725ad64d923c668e64e7c3898b5efde484cab49ce7f98c2885d2a13a9e355ad4", 16));
+
testECDSA239bitPrime();
testNONEwithECDSA239bitPrime();
testECDSA239bitBinary();
@@ -957,9 +1366,18 @@ public class DSATest
testECDSA239bitBinary("SHA384withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
testECDSA239bitBinary("SHA512withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+ testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_224, 224, new BigInteger("84d7d8e68e405064109cd9fc3e3026d74d278aada14ce6b7a9dd0380c154dc94", 16));
+ testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_256, 256, new BigInteger("99a43bdab4af989aaf2899079375642f2bae2dce05bcd8b72ec8c4a8d9a143f", 16));
+ testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_384, 384, new BigInteger("aa27726509c37aaf601de6f7e01e11c19add99530c9848381c23365dc505b11a", 16));
+ testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_512, 512, new BigInteger("f8306b57a1f5068bf12e53aabaae39e2658db39bc56747eaefb479995130ad16", 16));
+
testGeneration();
testParameters();
testDSA2Parameters();
+ testNullParameters();
+ testValidate();
+ testModified();
+ testKeyGenerationAll();
}
protected BigInteger[] derDecode(
@@ -992,7 +1410,7 @@ public class DSATest
}
private class DSATestSecureRandom
- extends FixedSecureRandom
+ extends TestRandomData
{
private boolean first = true;
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java
index a3e1a803..7a7baa87 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java
@@ -2,20 +2,14 @@ package org.bouncycastle.jce.provider.test;
import java.io.IOException;
import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -25,8 +19,8 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
public class DSTU4145Test
extends SimpleTest
@@ -65,8 +59,8 @@ public class DSTU4145Test
curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16), false),
new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16));
- SecureRandom k = new FixedSecureRandom(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00"));
- SecureRandom keyRand = new FixedSecureRandom(Hex.decode("0000955CD7E344303D1034E66933DC21C8044D42ADB8"));
+ SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00"));
+ SecureRandom keyRand = new TestRandomBigInteger(Hex.decode("0000955CD7E344303D1034E66933DC21C8044D42ADB8"));
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSTU4145", "BC");
keyGen.initialize(spec, keyRand);
@@ -114,7 +108,7 @@ public class DSTU4145Test
throws Exception
{
- SecureRandom k = new FixedSecureRandom(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00"));
+ SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00"));
ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, BigInteger.ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16));
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DetDSATest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DetDSATest.java
index 16c19694..8e75b474 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DetDSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DetDSATest.java
@@ -50,11 +50,16 @@ public class DetDSATest
PrivateKey privKey = keyFact.generatePrivate(privKeySpec);
- doTestHMACDetDSASample("SHA1withDETDSA", privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16));
- doTestHMACDetDSASample("SHA224withDETDSA", privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16));
- doTestHMACDetDSASample("SHA256withDETDSA", privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16));
- doTestHMACDetDSASample("SHA384withDETDSA", privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16));
- doTestHMACDetDSASample("SHA512withDETDSA", privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16));
+ doTestHMACDetDSASample("SHA1withDDSA", privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16));
+ doTestHMACDetDSASample("SHA224withDDSA", privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16));
+ doTestHMACDetDSASample("SHA256withDDSA", privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16));
+ doTestHMACDetDSASample("SHA384withDDSA", privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16));
+ doTestHMACDetDSASample("SHA512withDDSA", privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16));
+
+ doTestHMACDetDSATest("SHA3-224withDDSA", privKey, new BigInteger("58748b6ca41d25e41f7bfa51fed204a10a1bd1d3", 16), new BigInteger("86de2fdad0bc848dd20ddd9dc6253fc6d7553268", 16));
+ doTestHMACDetDSATest("SHA3-256withDDSA", privKey, new BigInteger("98c7a7906ada494285b3ab15cf9188a425f26bd4", 16), new BigInteger("21c5ed876037470d3959fa12f918674a4bf190e9", 16));
+ doTestHMACDetDSATest("SHA3-384withDDSA", privKey, new BigInteger("445ec584ec15c14abc67c99886a30a286cc83b33", 16), new BigInteger("21f564d5bb4b175e89a1a6fb2f27cd34c861142d", 16));
+ doTestHMACDetDSATest("SHA3-512withDDSA", privKey, new BigInteger("16918083f4c3ff4fc9b327e9e120a30ec39faaf6", 16), new BigInteger("1e9183a1dc7c20dbb596920cd94da3844a087203", 16));
}
private void doTestHMACDetDSASample(String algName, PrivateKey privKey, BigInteger r, BigInteger s)
@@ -63,6 +68,12 @@ public class DetDSATest
doTestHMACDetECDSA(Signature.getInstance(algName, "BC"), SAMPLE, privKey, r, s);
}
+ private void doTestHMACDetDSATest(String algName, PrivateKey privKey, BigInteger r, BigInteger s)
+ throws Exception
+ {
+ doTestHMACDetECDSA(Signature.getInstance(algName, "BC"), TEST, privKey, r, s);
+ }
+
// test vectors from appendix in RFC 6979
private void testECHMacDeterministic()
throws Exception
@@ -81,17 +92,22 @@ public class DetDSATest
PrivateKey privKey = keyFact.generatePrivate(privKeySpec);
- doTestHMACDetECDSASample("SHA1withDETECDSA", privKey, new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16));
- doTestHMACDetECDSASample("SHA224withDETECDSA", privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16));
- doTestHMACDetECDSASample("SHA256withDETECDSA", privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16));
- doTestHMACDetECDSASample("SHA384withDETECDSA", privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16));
- doTestHMACDetECDSASample("SHA512withDETECDSA", privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16));
-
- doTestHMACDetECDSATest("SHA1withDETECDSA", privKey, new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16));
- doTestHMACDetECDSATest("SHA224withDETECDSA", privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16));
- doTestHMACDetECDSATest("SHA256withDETECDSA", privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16));
- doTestHMACDetECDSATest("SHA384withDETECDSA", privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16));
- doTestHMACDetECDSATest("SHA512withDETECDSA", privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16));
+ doTestHMACDetECDSASample("SHA1withECDDSA", privKey, new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16));
+ doTestHMACDetECDSASample("SHA224withECDDSA", privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16));
+ doTestHMACDetECDSASample("SHA256withECDDSA", privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16));
+ doTestHMACDetECDSASample("SHA384withECDDSA", privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16));
+ doTestHMACDetECDSASample("SHA512withECDDSA", privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16));
+
+ doTestHMACDetECDSATest("SHA1withECDDSA", privKey, new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16));
+ doTestHMACDetECDSATest("SHA224withECDDSA", privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16));
+ doTestHMACDetECDSATest("SHA256withECDDSA", privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16));
+ doTestHMACDetECDSATest("SHA384withECDDSA", privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16));
+ doTestHMACDetECDSATest("SHA512withECDDSA", privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16));
+
+ doTestHMACDetECDSATest("SHA3-224withECDDSA", privKey, new BigInteger("abfcb817d04cc223f0d9c02c6db9230a91f955bf4556e0c6", 16), new BigInteger("ec2c29065a50d8ea39533d49472ccf538a5388cb31900e8f", 16));
+ doTestHMACDetECDSATest("SHA3-256withECDDSA", privKey, new BigInteger("a2c2d5362d3cea77191edb239bf22a14dcc59d6500a744fc", 16), new BigInteger("6c63f3012353082026be7e2c6f37e6d7811066ddc9b9ee47", 16));
+ doTestHMACDetECDSATest("SHA3-384withECDDSA", privKey, new BigInteger("2ff2c37d48cd6691c8adb9d2b1c1af203a1a6b8769c588dd", 16), new BigInteger("79c8171097f845c608dafd218ba096a51e0e4882faf2c08d", 16));
+ doTestHMACDetECDSATest("SHA3-512withECDDSA", privKey, new BigInteger("384619b82461f4cc852dfa1e87cd87105e8eb3cfd0fb6461", 16), new BigInteger("d0aac03f72e90942821e3af1f77fd8a6ae82d1ed31b8ed06", 16));
}
private void doTestHMACDetECDSASample(String sigAlg, PrivateKey privKey, BigInteger r, BigInteger s)
@@ -117,14 +133,13 @@ public class DetDSATest
ASN1Sequence seq = ASN1Sequence.getInstance(m);
-
if (!r.equals(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue()))
{
- fail("r value wrong");
+ fail("r value wrong, got " + ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().toString(16) + " expected " + r.toString(16));
}
if (!s.equals(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue()))
{
- fail("s value wrong");
+ fail("s value wrong, got " + ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().toString(16));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DigestTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DigestTest.java
index fd4b1c7f..96a81acd 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DigestTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/DigestTest.java
@@ -4,6 +4,7 @@ import java.security.MessageDigest;
import java.security.Security;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -50,6 +51,10 @@ public class DigestTest
{ MiscObjectIdentifiers.id_blake2b256.getId(), "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" },
{ MiscObjectIdentifiers.id_blake2b384.getId(), "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4" },
{ MiscObjectIdentifiers.id_blake2b512.getId(), "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" },
+ { "GOST3411-2012-256", "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" },
+ { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.getId(), "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" },
+ { "GOST3411-2012-512", "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" },
+ { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.getId(), "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" },
};
public String getName()
@@ -110,7 +115,7 @@ public class DigestTest
result2 = d.digest();
if (!MessageDigest.isEqual(result, result2))
- { System.err.println(Hex.toHexString(result2)); System.err.println(Hex.toHexString(result));
+ {
fail("Result object 4(b) not equal");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java
index 734711a3..7b74b52d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECDSA5Test.java
@@ -58,6 +58,7 @@ import org.bouncycastle.jce.ECKeyUtil;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.ECPointUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
@@ -65,6 +66,7 @@ import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
public class ECDSA5Test
extends SimpleTest
@@ -72,14 +74,102 @@ public class ECDSA5Test
byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
- SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 });
-
+ SecureRandom random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2)});
+ static final BigInteger PubX =
+ new BigInteger("3390396496586153202365024500890309020181905168626402195853036609"
+ + "0984128098564");
+ static final BigInteger PubY =
+ new BigInteger("1135421298983937257390683162600855221890652900790509030911087400"
+ + "65052129055287");
+ static final String[] VALID_SIGNATURES = {
+ "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49"
+ + "1b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285"
+ + "cd59f43260ecce",
+ };
+
+ // The following test vectors check for signature malleability and bugs. That means the test
+ // vectors are derived from a valid signature by modifying the ASN encoding. A correct
+ // implementation of ECDSA should only accept correct DER encoding and properly handle the
+ // others (e.g. integer overflow, infinity, redundant parameters, etc). Allowing alternative BER
+ // encodings is in many cases benign. An example where this kind of signature malleability was a
+ // problem: https://en.bitcoin.it/wiki/Transaction_Malleability
+ static final String[] MODIFIED_SIGNATURES = {
+ "304602812100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f"
+ + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "30470282002100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd"
+ + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "304602220000b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f"
+ + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f028120747291dd2f"
+ + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f02820020747291dd"
+ + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f022100747291dd2f"
+ + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "308145022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f"
+ + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "30820045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd"
+ + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce3000",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1000",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000",
+ "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000",
+ "3048022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce058100",
+ "3049022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce05820000",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1100",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0500",
+ "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce2500",
+ "3067022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f"
+ + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0220747291dd2f3f44af7ace68ea33431d6f"
+ + "94e418c106a6e76285cd59f43260ecce"
+ };
+
+ private void testModified()
+ throws Exception
+ {
+ ECNamedCurveParameterSpec namedCurve = ECNamedCurveTable.getParameterSpec("P-256");
+ org.bouncycastle.jce.spec.ECPublicKeySpec pubSpec = new org.bouncycastle.jce.spec.ECPublicKeySpec(namedCurve.getCurve().createPoint(PubX, PubY), namedCurve);
+ KeyFactory kFact = KeyFactory.getInstance("EC", "BC");
+ PublicKey pubKey = kFact.generatePublic(pubSpec);
+ Signature sig = Signature.getInstance("SHA256WithECDSA", "BC");
+
+ for (int i = 0; i != MODIFIED_SIGNATURES.length; i++)
+ {
+ sig.initVerify(pubKey);
+
+ sig.update(Strings.toByteArray("Hello"));
+
+ boolean failed;
+
+ try
+ {
+ failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i]));
+ }
+ catch (SignatureException e)
+ {
+ failed = true;
+ }
+
+ isTrue("sig verified when shouldn't: " + i, failed);
+ }
+ }
+
private void decodeTest()
{
EllipticCurve curve = new EllipticCurve(
- new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q
- new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
- new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
+ new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+ new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
ECPoint p = ECPointUtil.decodePoint(curve, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"));
@@ -107,7 +197,7 @@ public class ECDSA5Test
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
EllipticCurve curve = new EllipticCurve(
new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
@@ -119,7 +209,7 @@ public class ECDSA5Test
ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
1); // h
-
+
ECPrivateKeySpec priKey = new ECPrivateKeySpec(
new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
@@ -129,18 +219,18 @@ public class ECDSA5Test
ECPointUtil.decodePoint(curve, Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
spec);
- Signature sgr = Signature.getInstance("ECDSA", "BC");
- KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
- PrivateKey sKey = f.generatePrivate(priKey);
- PublicKey vKey = f.generatePublic(pubKey);
+ Signature sgr = Signature.getInstance("ECDSA", "BC");
+ KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
+ PrivateKey sKey = f.generatePrivate(priKey);
+ PublicKey vKey = f.generatePublic(pubKey);
sgr.initSign(sKey, k);
- byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+ byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'};
sgr.update(message);
- byte[] sigBytes = sgr.sign();
+ byte[] sigBytes = sgr.sign();
sgr.initVerify(vKey);
@@ -151,7 +241,7 @@ public class ECDSA5Test
fail("239 Bit EC verification failed");
}
- BigInteger[] sig = derDecode(sigBytes);
+ BigInteger[] sig = derDecode(sigBytes);
if (!r.equals(sig[0]))
{
@@ -179,21 +269,21 @@ public class ECDSA5Test
KeyPair kp = kpGen.generateKeyPair();
byte[] data = "Hello World!!!".getBytes();
- String[] cvcAlgs = { "SHA1WITHCVC-ECDSA", "SHA224WITHCVC-ECDSA",
- "SHA256WITHCVC-ECDSA", "SHA384WITHCVC-ECDSA",
- "SHA512WITHCVC-ECDSA" };
- String[] cvcOids = { EACObjectIdentifiers.id_TA_ECDSA_SHA_1.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_224.getId(),
- EACObjectIdentifiers.id_TA_ECDSA_SHA_256.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_384.getId(),
- EACObjectIdentifiers.id_TA_ECDSA_SHA_512.getId() };
+ String[] cvcAlgs = {"SHA1WITHCVC-ECDSA", "SHA224WITHCVC-ECDSA",
+ "SHA256WITHCVC-ECDSA", "SHA384WITHCVC-ECDSA",
+ "SHA512WITHCVC-ECDSA"};
+ String[] cvcOids = {EACObjectIdentifiers.id_TA_ECDSA_SHA_1.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_224.getId(),
+ EACObjectIdentifiers.id_TA_ECDSA_SHA_256.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_384.getId(),
+ EACObjectIdentifiers.id_TA_ECDSA_SHA_512.getId()};
testBsiAlgorithms(kp, data, cvcAlgs, cvcOids);
- String[] plainAlgs = { "SHA1WITHPLAIN-ECDSA", "SHA224WITHPLAIN-ECDSA",
- "SHA256WITHPLAIN-ECDSA", "SHA384WITHPLAIN-ECDSA",
- "SHA512WITHPLAIN-ECDSA", "RIPEMD160WITHPLAIN-ECDSA" };
- String[] plainOids = { BSIObjectIdentifiers.ecdsa_plain_SHA1.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA224.getId(),
- BSIObjectIdentifiers.ecdsa_plain_SHA256.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA384.getId(),
- BSIObjectIdentifiers.ecdsa_plain_SHA512.getId(), BSIObjectIdentifiers.ecdsa_plain_RIPEMD160.getId() };
+ String[] plainAlgs = {"SHA1WITHPLAIN-ECDSA", "SHA224WITHPLAIN-ECDSA",
+ "SHA256WITHPLAIN-ECDSA", "SHA384WITHPLAIN-ECDSA",
+ "SHA512WITHPLAIN-ECDSA", "RIPEMD160WITHPLAIN-ECDSA"};
+ String[] plainOids = {BSIObjectIdentifiers.ecdsa_plain_SHA1.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA224.getId(),
+ BSIObjectIdentifiers.ecdsa_plain_SHA256.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA384.getId(),
+ BSIObjectIdentifiers.ecdsa_plain_SHA512.getId(), BSIObjectIdentifiers.ecdsa_plain_RIPEMD160.getId()};
testBsiAlgorithms(kp, data, plainAlgs, plainOids);
}
@@ -233,42 +323,42 @@ public class ECDSA5Test
{
BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
-
+
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
EllipticCurve curve = new EllipticCurve(
new ECFieldF2m(239, // m
- new int[] { 36 }), // k
+ new int[]{36}), // k
new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
-
+
ECParameterSpec params = new ECParameterSpec(
curve,
ECPointUtil.decodePoint(curve, Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
4); // h
-
+
ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec(
new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
params);
-
+
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
ECPointUtil.decodePoint(curve, Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
params);
-
- Signature sgr = Signature.getInstance("ECDSA", "BC");
- KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
- PrivateKey sKey = f.generatePrivate(priKeySpec);
- PublicKey vKey = f.generatePublic(pubKeySpec);
- byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
-
+
+ Signature sgr = Signature.getInstance("ECDSA", "BC");
+ KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
+ PrivateKey sKey = f.generatePrivate(priKeySpec);
+ PublicKey vKey = f.generatePublic(pubKeySpec);
+ byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'};
+
sgr.initSign(sKey, k);
sgr.update(message);
-
- byte[] sigBytes = sgr.sign();
+
+ byte[] sigBytes = sgr.sign();
sgr.initVerify(vKey);
@@ -279,7 +369,7 @@ public class ECDSA5Test
fail("239 Bit EC verification failed");
}
- BigInteger[] sig = derDecode(sigBytes);
+ BigInteger[] sig = derDecode(sigBytes);
if (!r.equals(sig[0]))
{
@@ -295,14 +385,14 @@ public class ECDSA5Test
+ " got : " + sig[1]);
}
}
-
+
private void testGeneration()
throws Exception
{
//
// ECDSA generation test
//
- byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+ byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Signature s = Signature.getInstance("ECDSA", "BC");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
@@ -322,7 +412,7 @@ public class ECDSA5Test
KeyPair p = g.generateKeyPair();
PrivateKey sKey = p.getPrivate();
- PublicKey vKey = p.getPublic();
+ PublicKey vKey = p.getPublic();
s.initSign(sKey);
@@ -376,8 +466,8 @@ public class ECDSA5Test
{
KeyFactory ecFact = KeyFactory.getInstance("ECDSA");
- ECPublicKeySpec pubSpec = (ECPublicKeySpec)ecFact.getKeySpec(pub, ECPublicKeySpec.class);
- ECPrivateKeySpec privSpec = (ECPrivateKeySpec)ecFact.getKeySpec(priv, ECPrivateKeySpec.class);
+ ECPublicKeySpec pubSpec = (ECPublicKeySpec)ecFact.getKeySpec(pub, ECPublicKeySpec.class);
+ ECPrivateKeySpec privSpec = (ECPrivateKeySpec)ecFact.getKeySpec(priv, ECPrivateKeySpec.class);
if (!pubSpec.getW().equals(pub.getW()) || !pubSpec.getParams().getCurve().equals(pub.getParams().getCurve()))
{
@@ -389,8 +479,8 @@ public class ECDSA5Test
fail("privSpec not correct");
}
- ECPublicKey pubKey = (ECPublicKey)ecFact.translateKey(pub);
- ECPrivateKey privKey = (ECPrivateKey)ecFact.translateKey(priv);
+ ECPublicKey pubKey = (ECPublicKey)ecFact.translateKey(pub);
+ ECPrivateKey privKey = (ECPrivateKey)ecFact.translateKey(priv);
if (!pubKey.getW().equals(pub.getW()) || !pubKey.getParams().getCurve().equals(pub.getParams().getCurve()))
{
@@ -452,7 +542,7 @@ public class ECDSA5Test
KeyPair pair = kpGen.generateKeyPair();
final PrivateKey privKey = pair.getPrivate();
- final PublicKey pubKey = pair.getPublic();
+ final PublicKey pubKey = pair.getPublic();
Signature s = Signature.getInstance("ECDSA", "BC");
@@ -667,7 +757,7 @@ public class ECDSA5Test
pair = kpGen.generateKeyPair();
final PrivateKey privRsa = pair.getPrivate();
- final PublicKey pubRsa = pair.getPublic();
+ final PublicKey pubRsa = pair.getPublic();
try
{
@@ -925,24 +1015,24 @@ public class ECDSA5Test
}
/**
- COUNT = 1
- dsCAVS = 00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0
- QsCAVSx = 000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764
- QsCAVSy = 000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9
- NonceEphemCAVS = 4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8
- dsIUT = 000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd
- QsIUTx = 00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7
- QsIUTy = 00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3
- deIUT = 00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e
- QeIUTx = 000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120
- QeIUTy = 000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a
- OI = a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8
- CAVSTag = 4ade5dc983cc1cf61c90fdbf726fa6a88e9bf411bbaf0015db06ff4348560e4d
- Z = 019a19a0a99f60221ee23323b3317292e8c10d57ba04e0b33f6241979ec3895945eed0bdcbc59ab576e7047061f0d63d1aaf78b1d442028605aa1c0f963a3bc9d61a
- MacData = 4b435f315f55a1b2c3d4e543415653696401b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf0112000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8
- DKM = 0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426
- Result = P (14 - DKM value should have leading 0 nibble )
- */
+ * COUNT = 1
+ * dsCAVS = 00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0
+ * QsCAVSx = 000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764
+ * QsCAVSy = 000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9
+ * NonceEphemCAVS = 4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8
+ * dsIUT = 000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd
+ * QsIUTx = 00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7
+ * QsIUTy = 00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3
+ * deIUT = 00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e
+ * QeIUTx = 000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120
+ * QeIUTy = 000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a
+ * OI = a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8
+ * CAVSTag = 4ade5dc983cc1cf61c90fdbf726fa6a88e9bf411bbaf0015db06ff4348560e4d
+ * Z = 019a19a0a99f60221ee23323b3317292e8c10d57ba04e0b33f6241979ec3895945eed0bdcbc59ab576e7047061f0d63d1aaf78b1d442028605aa1c0f963a3bc9d61a
+ * MacData = 4b435f315f55a1b2c3d4e543415653696401b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf0112000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8
+ * DKM = 0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426
+ * Result = P (14 - DKM value should have leading 0 nibble )
+ */
public void testMQVwithHMACOnePass()
throws Exception
{
@@ -954,17 +1044,17 @@ public class ECDSA5Test
KeyFactory keyFact = KeyFactory.getInstance("EC", "BC");
ECPrivateKey dsCAVS = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0", 16), ecSpec));
- ECPublicKey qsCAVS = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
- new BigInteger("000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764", 16),
- new BigInteger("000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9", 16)), ecSpec));
+ ECPublicKey qsCAVS = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
+ new BigInteger("000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764", 16),
+ new BigInteger("000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9", 16)), ecSpec));
ECPrivateKey dsIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd", 16), ecSpec));
- ECPublicKey qsIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
- new BigInteger("00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7", 16),
- new BigInteger("00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3", 16)), ecSpec));
+ ECPublicKey qsIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
+ new BigInteger("00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7", 16),
+ new BigInteger("00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3", 16)), ecSpec));
ECPrivateKey deIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e", 16), ecSpec));
- ECPublicKey qeIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
+ ECPublicKey qeIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint(
new BigInteger("000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120", 16),
new BigInteger("000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a", 16)), ecSpec));
@@ -997,14 +1087,14 @@ public class ECDSA5Test
}
protected BigInteger[] derDecode(
- byte[] encoding)
+ byte[] encoding)
throws IOException
{
- ByteArrayInputStream bIn = new ByteArrayInputStream(encoding);
- ASN1InputStream aIn = new ASN1InputStream(bIn);
- ASN1Sequence s = (ASN1Sequence)aIn.readObject();
+ ByteArrayInputStream bIn = new ByteArrayInputStream(encoding);
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+ ASN1Sequence s = (ASN1Sequence)aIn.readObject();
- BigInteger[] sig = new BigInteger[2];
+ BigInteger[] sig = new BigInteger[2];
sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue();
sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue();
@@ -1032,10 +1122,11 @@ public class ECDSA5Test
testBSI();
testMQVwithHMACOnePass();
testAlgorithmParameters();
+ testModified();
}
public static void main(
- String[] args)
+ String[] args)
{
Security.addProvider(new BouncyCastleProvider());
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESTest.java
index ad2b8b25..059fa19a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESTest.java
@@ -5,8 +5,11 @@ import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
+import java.security.spec.ECGenParameterSpec;
+import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
+import javax.crypto.SealedObject;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.digests.SHA1Digest;
@@ -20,6 +23,7 @@ import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.IESParameterSpec;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -73,19 +77,10 @@ public class ECIESTest
new HMac(new SHA1Digest()),
new PaddedBufferedBlockCipher(new DESEngine())));
- params = new IESParameterSpec(derivation, encoding, 128, 128);
+ params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("0001020304050607"));
// Testing ECIES with default curve using DES
g = KeyPairGenerator.getInstance("EC", "BC");
- doTest("default", g, "ECIESwithDESEDE", params);
-
- // Testing ECIES with 192-bit curve using DES
- g.initialize(192, new SecureRandom());
- doTest("192-bit", g, "ECIESwithDESEDE", params);
-
- // Testing ECIES with 256-bit curve using DES
- g.initialize(256, new SecureRandom());
- doTest("256-bit", g, "ECIESwithDESEDE", params);
// Testing ECIES with 256-bit curve using DES-CBC
g.initialize(256, new SecureRandom());
@@ -110,21 +105,9 @@ public class ECIESTest
}
}
- c1 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAES();
- c2 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAES();
- params = new IESParameterSpec(derivation, encoding, 128, 128);
-
- // Testing ECIES with default curve using AES
- g = KeyPairGenerator.getInstance("EC", "BC");
- doTest("default", g, "ECIESwithAES", params);
-
- // Testing ECIES with 192-bit curve using AES
- g.initialize(192, new SecureRandom());
- doTest("192-bit", g, "ECIESwithAES", params);
-
- // Testing ECIES with 256-bit curve using AES
- g.initialize(256, new SecureRandom());
- doTest("256-bit", g, "ECIESwithAES", params);
+ c1 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC();
+ c2 = new org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC();
+ params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("000102030405060708090a0b0c0d0e0f"));
// Testing ECIES with 256-bit curve using AES-CBC
g.initialize(256, new SecureRandom());
@@ -148,6 +131,76 @@ public class ECIESTest
fail("AES wrong message!");
}
}
+
+ KeyPair keyPair = g.generateKeyPair();
+ ECPublicKey pub = (ECPublicKey)keyPair.getPublic();
+ ECPrivateKey priv = (ECPrivateKey)keyPair.getPrivate();
+
+ Cipher c = Cipher.getInstance("ECIESwithAES-CBC", "BC");
+
+ try
+ {
+ c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null));
+
+ fail("no exception");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
+
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, priv);
+
+ fail("no exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+ isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
+
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null));
+
+ fail("no exception");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage()));
+ }
+
+ sealedObjectTest();
+ }
+
+ private void sealedObjectTest()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES");
+ kpg.initialize(new ECGenParameterSpec("secp256r1"));
+ KeyPair keyPair = kpg.generateKeyPair();
+
+ Cipher cipher = Cipher.getInstance("ECIES");
+ cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
+
+ String toEncrypt = "Hello";
+
+ // Check that cipher works ok
+ cipher.doFinal(toEncrypt.getBytes());
+
+ // Using a SealedObject to encrypt the same string fails with a NullPointerException
+ SealedObject sealedObject = new SealedObject(toEncrypt, cipher);
+
+ cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+
+ String result = (String)sealedObject.getObject(cipher);
+
+ isTrue("result wrong", result.equals(toEncrypt));
+
+ result = (String)sealedObject.getObject(keyPair.getPrivate());
+
+ isTrue("result wrong", result.equals(toEncrypt));
}
public void doTest(
@@ -171,7 +224,10 @@ public class ECIESTest
// Testing with null parameters and DHAES mode off
c1.init(Cipher.ENCRYPT_MODE, Pub, new SecureRandom());
- c2.init(Cipher.DECRYPT_MODE, Priv, new SecureRandom());
+ c2.init(Cipher.DECRYPT_MODE, Priv, c1.getParameters());
+
+ isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV()));
+
out1 = c1.doFinal(message, 0, message.length);
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
@@ -180,13 +236,33 @@ public class ECIESTest
// Testing with given parameters and DHAES mode off
c1.init(Cipher.ENCRYPT_MODE, Pub, p, new SecureRandom());
- c2.init(Cipher.DECRYPT_MODE, Priv, p, new SecureRandom());
+ c2.init(Cipher.DECRYPT_MODE, Priv, p);
out1 = c1.doFinal(message, 0, message.length);
out2 = c2.doFinal(out1, 0, out1.length);
if (!areEqual(out2, message))
fail(testname + " test failed with non-null parameters, DHAES mode false.");
+ //
+ // corrupted data test
+ //
+ int offset = out1.length - (message.length + 8);
+ byte[] tmp = new byte[out1.length];
+ for (int i = offset; i != out1.length; i++)
+ {
+ System.arraycopy(out1, 0, tmp, 0, tmp.length);
+ tmp[i] = (byte)~tmp[i];
+
+ try
+ {
+ c2.doFinal(tmp, 0, tmp.length);
+ fail("decrypted corrupted data");
+ }
+ catch (BadPaddingException e)
+ {
+ isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage()));
+ }
+ }
// TODO: DHAES mode is not currently implemented, perhaps it shouldn't be...
// c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC");
// c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC");
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java
index 95589561..cfbdf061 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECIESVectorTest.java
@@ -117,13 +117,14 @@ public class ECIESVectorTest
doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), p256_1_with_params22);
doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), p256_1_with_params23);
- doTestNoParams("ECIES with P-256 None", keyPair, "OldECIES", p256_1_eph, old_p256_1_no_params);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), old_p256_1_with_params11);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), old_p256_1_with_params12);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), old_p256_1_with_params13);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), old_p256_1_with_params21);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), old_p256_1_with_params22);
- doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), old_p256_1_with_params23);
+ // no longer supported
+// doTestNoParams("ECIES with P-256 None", keyPair, "OldECIES", p256_1_eph, old_p256_1_no_params);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), old_p256_1_with_params11);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), old_p256_1_with_params12);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), old_p256_1_with_params13);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), old_p256_1_with_params21);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), old_p256_1_with_params22);
+// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), old_p256_1_with_params23);
keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p256_2_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p256_2_pri)));
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECNRTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECNRTest.java
index 165faa73..98b10582 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECNRTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ECNRTest.java
@@ -23,6 +23,7 @@ import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
public class ECNRTest
extends SimpleTest
@@ -30,8 +31,9 @@ public class ECNRTest
byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
- SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 });
-
+ SecureRandom random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) });
+
/**
* X9.62 - 1998,<br>
* J.3.2, Page 155, ECDSA over the field Fp<br>
@@ -45,7 +47,7 @@ public class ECNRTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve curve = new ECCurve.Fp(
new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
@@ -89,7 +91,7 @@ public class ECNRTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("dcc5d1f1020906df2782360d36b2de7a17ece37d503784af", 16));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve.Fp curve = new ECCurve.Fp(
new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q (or p)
@@ -133,7 +135,7 @@ public class ECNRTest
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", 16));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
ECCurve.Fp curve = new ECCurve.Fp(
new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ElGamalTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ElGamalTest.java
index 2ff08510..e2d24e66 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ElGamalTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ElGamalTest.java
@@ -14,6 +14,7 @@ import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
import javax.crypto.Cipher;
import javax.crypto.interfaces.DHPrivateKey;
@@ -471,6 +472,36 @@ public class ElGamalTest
}
}
+ public void testGetExceptionsPKCS1()
+ throws Exception
+ {
+ SecureRandom rand = new SecureRandom();
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance("ELGAMAL", "BC");
+ keygen.initialize(new DHParameterSpec(p1024, g1024), rand);
+ KeyPair keypair = keygen.genKeyPair();
+
+ Cipher c = Cipher.getInstance("ELGAMAL/ECB/PKCS1Padding", "BC");
+ byte[] ciphertext = new byte[1024 / 8];
+ HashSet<String> exceptions = new HashSet<String>();
+ final int SAMPLES = 1000;
+ for (int i = 0; i < SAMPLES; i++)
+ {
+ rand.nextBytes(ciphertext);
+ ciphertext[0] = (byte)0;
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, keypair.getPrivate());
+ c.doFinal(ciphertext);
+ }
+ catch (Exception ex)
+ {
+ String message = ex.toString();
+ exceptions.add(message);
+ }
+ }
+ isTrue("exception count wrong", 1 == exceptions.size());
+ }
+
public void performTest()
throws Exception
{
@@ -485,6 +516,7 @@ public class ElGamalTest
testGP(1024, 256, g1024, p1024);
testRandom(256);
+ testGetExceptionsPKCS1();
}
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/GOST3410Test.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
index 71378bb3..a7cc7a28 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
@@ -44,8 +44,8 @@ import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomBigInteger;
import org.bouncycastle.x509.X509V3CertificateGenerator;
public class GOST3410Test
@@ -60,7 +60,7 @@ public class GOST3410Test
byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395"));
- SecureRandom k = new FixedSecureRandom(kData);
+ SecureRandom k = new TestRandomBigInteger(kData);
BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/HMacTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/HMacTest.java
index 06e1429c..ff1f2d58 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/HMacTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/HMacTest.java
@@ -3,15 +3,20 @@ package org.bouncycastle.jce.provider.test;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Security;
+import java.util.Arrays;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.RC5ParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -22,42 +27,50 @@ import org.bouncycastle.util.test.SimpleTest;
public class HMacTest
extends SimpleTest
{
- static byte[] keyBytes = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
- static byte[] message = "Hi There".getBytes();
- static byte[] output1 = Hex.decode("b617318655057264e28bc0b6fb378c8ef146be00");
- static byte[] outputMD5 = Hex.decode("5ccec34ea9656392457fa1ac27f08fbc");
- static byte[] outputMD2 = Hex.decode("dc1923ef5f161d35bef839ca8c807808");
- static byte[] outputMD4 = Hex.decode("5570ce964ba8c11756cdc3970278ff5a");
- static byte[] output224 = Hex.decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22");
- static byte[] output256 = Hex.decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
- static byte[] output384 = Hex.decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6");
- static byte[] output512 = Hex.decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854");
- static byte[] output512_224 = Hex.decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039");
- static byte[] output512_256 = Hex.decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab");
- static byte[] outputRipeMD128 = Hex.decode("fda5717fb7e20cf05d30bb286a44b05d");
- static byte[] outputRipeMD160 = Hex.decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668");
- static byte[] outputTiger = Hex.decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647");
- static byte[] outputOld384 = Hex.decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40");
- static byte[] outputOld512 = Hex.decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a");
-
- static byte[] outputKck224 = Hex.decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc");
- static byte[] outputKck256 = Hex.decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821");
- static byte[] outputKck288 = Hex.decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441");
- static byte[] outputKck384 = Hex.decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048");
- static byte[] outputKck512 = Hex.decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755");
+ static byte[] keyBytes = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+ static byte[] message = Hex.decode("4869205468657265");
+ static byte[] output1 = Hex.decode("b617318655057264e28bc0b6fb378c8ef146be00");
+ static byte[] outputMD5 = Hex.decode("5ccec34ea9656392457fa1ac27f08fbc");
+ static byte[] outputMD2 = Hex.decode("dc1923ef5f161d35bef839ca8c807808");
+ static byte[] outputMD4 = Hex.decode("5570ce964ba8c11756cdc3970278ff5a");
+ static byte[] output224 = Hex.decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22");
+ static byte[] output256 = Hex.decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
+ static byte[] output384 = Hex.decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6");
+ static byte[] output512 = Hex.decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854");
+ static byte[] output512_224 = Hex.decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039");
+ static byte[] output512_256 = Hex.decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab");
+ static byte[] outputRipeMD128 = Hex.decode("fda5717fb7e20cf05d30bb286a44b05d");
+ static byte[] outputRipeMD160 = Hex.decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668");
+ static byte[] outputTiger = Hex.decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647");
+ static byte[] outputOld384 = Hex.decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40");
+ static byte[] outputOld512 = Hex.decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a");
+
+ static byte[] outputKck224 = Hex.decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc");
+ static byte[] outputKck256 = Hex.decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821");
+ static byte[] outputKck288 = Hex.decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441");
+ static byte[] outputKck384 = Hex.decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048");
+ static byte[] outputKck512 = Hex.decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755");
+
+ static byte[] outputSha3_224 = Hex.decode("3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7");
+ static byte[] outputSha3_256 = Hex.decode("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb");
+ static byte[] outputSha3_384 = Hex.decode("68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd");
+ static byte[] outputSha3_512 = Hex.decode("eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e");
+
+ static byte[] outputGost2012_256 = Hex.decode("f03422dfa37a507ca126ce01b8eba6b7fdda8f8a60dd8f2703e3a372120b8294");
+ static byte[] outputGost2012_512 = Hex.decode("86b6a06bfa9f1974aff6ccd7fa3f835f0bd850395d6084efc47b9dda861a2cdf0dcaf959160733d5269f6567966dd7a9f932a77cd6f080012cd476f1c2cc31bb");
public HMacTest()
{
}
public void testHMac(
- String hmacName,
- byte[] output)
+ String hmacName,
+ byte[] output)
throws Exception
{
- SecretKey key = new SecretKeySpec(keyBytes, hmacName);
- byte[] out;
- Mac mac;
+ SecretKey key = new SecretKeySpec(keyBytes, hmacName);
+ byte[] out;
+ Mac mac;
mac = Mac.getInstance(hmacName, "BC");
@@ -89,6 +102,45 @@ public class HMacTest
out = mac.doFinal();
}
+ public void testHMac(
+ String hmacName,
+ int defKeySize,
+ byte[] output)
+ throws Exception
+ {
+ SecretKey key = new SecretKeySpec(keyBytes, hmacName);
+ byte[] out;
+ Mac mac;
+
+ mac = Mac.getInstance(hmacName, "BC");
+
+ mac.init(key);
+
+ mac.reset();
+
+ mac.update(message, 0, message.length);
+
+ out = mac.doFinal();
+
+ if (!areEqual(out, output))
+ {
+ fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out)));
+ }
+
+ KeyGenerator kGen = KeyGenerator.getInstance(hmacName, "BC");
+
+ SecretKey secretKey = kGen.generateKey();
+
+ mac.init(secretKey);
+
+ mac.update(message);
+
+ out = mac.doFinal();
+
+ isTrue("default key wrong length", secretKey.getEncoded().length == defKeySize / 8);
+ }
+
+
private void testExceptions()
throws Exception
{
@@ -96,7 +148,7 @@ public class HMacTest
mac = Mac.getInstance("HmacSHA1", "BC");
- byte [] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5};
+ byte[] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5};
SecretKeySpec sks = new SecretKeySpec(b, "HmacSHA1");
RC5ParameterSpec algPS = new RC5ParameterSpec(100, 100, 100);
@@ -135,52 +187,127 @@ public class HMacTest
public void performTest()
throws Exception
{
- testHMac("HMac-SHA1", output1);
+ testHMac("HMac-SHA1", 160, output1);
testHMac("HMac-MD5", outputMD5);
testHMac("HMac-MD4", outputMD4);
testHMac("HMac-MD2", outputMD2);
- testHMac("HMac-SHA224", output224);
- testHMac("HMac-SHA256", output256);
- testHMac("HMac-SHA384", output384);
- testHMac("HMac-SHA512", output512);
+ testHMac("HMac-SHA224", 224, output224);
+ testHMac("HMac-SHA256", 256, output256);
+ testHMac("HMac-SHA384", 384, output384);
+ testHMac("HMac-SHA512", 512, output512);
testHMac("HMac-SHA512/224", output512_224);
testHMac("HMac-SHA512/256", output512_256);
- testHMac("HMac-RIPEMD128", outputRipeMD128);
- testHMac("HMac-RIPEMD160", outputRipeMD160);
- testHMac("HMac-TIGER", outputTiger);
- testHMac("HMac-KECCAK224", outputKck224);
- testHMac("HMac-KECCAK256", outputKck256);
- testHMac("HMac-KECCAK288", outputKck288);
- testHMac("HMac-KECCAK384", outputKck384);
- testHMac("HMac-KECCAK512", outputKck512);
+ testHMac("HMac-RIPEMD128", 128, outputRipeMD128);
+ testHMac("HMac-RIPEMD160", 160, outputRipeMD160);
+ testHMac("HMac-TIGER", 192, outputTiger);
+ testHMac("HMac-KECCAK224", 224, outputKck224);
+ testHMac("HMac-KECCAK256", 256, outputKck256);
+ testHMac("HMac-KECCAK288", 288, outputKck288);
+ testHMac("HMac-KECCAK384", 384, outputKck384);
+ testHMac("HMac-KECCAK512", 512, outputKck512);
+ testHMac("HMac-SHA3-224", 224, outputSha3_224);
+ testHMac("HMac-SHA3-256", 256, outputSha3_256);
+ testHMac("HMac-SHA3-384", 384, outputSha3_384);
+ testHMac("HMac-SHA3-512", 512, outputSha3_512);
+
+ testHMac("HMac-GOST3411-2012-256", 256, outputGost2012_256);
+ testHMac("HMac-GOST3411-2012-512", 512, outputGost2012_512);
testHMac("HMac/SHA1", output1);
testHMac("HMac/MD5", outputMD5);
testHMac("HMac/MD4", outputMD4);
testHMac("HMac/MD2", outputMD2);
- testHMac("HMac/SHA224", output224);
- testHMac("HMac/SHA256", output256);
- testHMac("HMac/SHA384", output384);
- testHMac("HMac/SHA512", output512);
- testHMac("HMac/RIPEMD128", outputRipeMD128);
- testHMac("HMac/RIPEMD160", outputRipeMD160);
- testHMac("HMac/TIGER", outputTiger);
-
- testHMac(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), output1);
- testHMac(PKCSObjectIdentifiers.id_hmacWithSHA224.getId(), output224);
- testHMac(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), output256);
- testHMac(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), output384);
- testHMac(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), output512);
- testHMac(IANAObjectIdentifiers.hmacSHA1.getId(), output1);
+ testHMac("HMac/SHA224", 224, output224);
+ testHMac("HMac/SHA256", 256, output256);
+ testHMac("HMac/SHA384", 384, output384);
+ testHMac("HMac/SHA512", 512, output512);
+ testHMac("HMac/RIPEMD128", 128, outputRipeMD128);
+ testHMac("HMac/RIPEMD160", 160, outputRipeMD160);
+ testHMac("HMac/TIGER", 192, outputTiger);
+ testHMac("HMac/KECCAK224", 224, outputKck224);
+ testHMac("HMac/KECCAK256", 256, outputKck256);
+ testHMac("HMac/KECCAK288", 288, outputKck288);
+ testHMac("HMac/KECCAK384", 384, outputKck384);
+ testHMac("HMac/KECCAK512", 512, outputKck512);
+ testHMac("HMac/SHA3-224", 224, outputSha3_224);
+ testHMac("HMac/SHA3-256", 256, outputSha3_256);
+ testHMac("HMac/SHA3-384", 384, outputSha3_384);
+ testHMac("HMac/SHA3-512", 512, outputSha3_512);
+ testHMac("HMac/GOST3411-2012-256", 256, outputGost2012_256);
+ testHMac("HMac/GOST3411-2012-512", 512, outputGost2012_512);
+
+ testHMac(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), 160, output1);
+ testHMac(PKCSObjectIdentifiers.id_hmacWithSHA224.getId(), 224, output224);
+ testHMac(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), 256, output256);
+ testHMac(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), 384, output384);
+ testHMac(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), 512, output512);
+ testHMac(IANAObjectIdentifiers.hmacSHA1.getId(), 160, output1);
testHMac(IANAObjectIdentifiers.hmacMD5.getId(), outputMD5);
- testHMac(IANAObjectIdentifiers.hmacRIPEMD160.getId(), outputRipeMD160);
- testHMac(IANAObjectIdentifiers.hmacTIGER.getId(), outputTiger);
+ testHMac(IANAObjectIdentifiers.hmacRIPEMD160.getId(), 160, outputRipeMD160);
+ testHMac(IANAObjectIdentifiers.hmacTIGER.getId(), 192, outputTiger);
+
+ testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_224.getId(), 224, outputSha3_224);
+ testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_256.getId(), 256, outputSha3_256);
+ testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_384.getId(), 384, outputSha3_384);
+ testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_512.getId(), 512, outputSha3_512);
+
+ testHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256.getId(), 256, outputGost2012_256);
+ testHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512.getId(), 512, outputGost2012_512);
// test for compatibility with broken HMac.
testHMac("OldHMacSHA384", outputOld384);
testHMac("OldHMacSHA512", outputOld512);
testExceptions();
+
+ testPBEWITHHMACSHAVariants();
+ }
+
+ private static final int[] SUN_JCA_VARIANTS = {
+ 1, 224, 256, 384, 512
+ };
+
+ private static final byte[][] SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS = {
+ Hex.decode("2cb29f938331443af79de5863a1b072d57a4b640"),
+ Hex.decode("3bf31c354fb1817503e9b581d4d1d51c4c8e921a3b46a513cc24c0ca"),
+ Hex.decode("583697860e49d8d534ebdf99205173356f4e209447b6ac7d500ddddc1b382068"),
+ Hex.decode("ad3ca42cc656876872bd0e5054d0f2260ec2a07635c5dfa655926989af392bbe636a23f08d1dc8ccd966ffa66ecc30e0"),
+ Hex.decode("eabbb30bf280870530126bea40d3123c18d6bd6f6e9ded0eebd51a44d8527b27732206bd1bb7c1c8d941b5f2fba2f87ed49f5f1f3d7bef0e7547d335b4a55b87")
+ };
+
+ /**
+ * Test that BC has the same results as the SunJCA provider for PBEwithHMACSHA.
+ * <p>
+ * Test courtesy of the Android project.
+ * </p>
+ */
+ public void testPBEWITHHMACSHAVariants()
+ throws Exception
+ {
+ byte[] plaintext = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34};
+ byte[] salt = "saltsalt".getBytes();
+ char[] password = "password".toCharArray();
+ int iterationCount = 100;
+
+ for (int shaVariantIndex = 0; shaVariantIndex < SUN_JCA_VARIANTS.length; shaVariantIndex++)
+ {
+ int shaVariant = SUN_JCA_VARIANTS[shaVariantIndex];
+ SecretKeyFactory secretKeyFactory =
+ SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA" + shaVariant, "BC");
+ PBEKeySpec pbeKeySpec = new PBEKeySpec(password,
+ salt,
+ iterationCount,
+ // Key depending on block size!
+ (shaVariant < 384) ? 64 : 128);
+ SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);
+ Mac mac = Mac.getInstance("PBEWITHHMACSHA" + shaVariant, "BC");
+ mac.init(secretKey);
+
+ byte[] bcResult = mac.doFinal(plaintext);
+
+ isTrue("value mismatch", Arrays.equals(SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS[shaVariantIndex], bcResult));
+ }
}
public String getName()
@@ -189,7 +316,7 @@ public class HMacTest
}
public static void main(
- String[] args)
+ String[] args)
{
Security.addProvider(new BouncyCastleProvider());
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java
index fa90108e..eb7c0dd3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java
@@ -36,7 +36,8 @@ public class ImplicitlyCaTest
byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
- SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 });
+ SecureRandom random = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) });
public void performTest()
throws Exception
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java
index 3a8693d4..bf660bee 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/NamedCurveTest.java
@@ -1,15 +1,5 @@
package org.bouncycastle.jce.provider.test;
-import org.bouncycastle.asn1.nist.NISTNamedCurves;
-import org.bouncycastle.asn1.sec.SECNamedCurves;
-import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
-import org.bouncycastle.asn1.x9.X962NamedCurves;
-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jce.spec.ECNamedCurveSpec;
-import org.bouncycastle.util.test.SimpleTest;
-
-import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
@@ -22,12 +12,28 @@ import java.security.Signature;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
-import java.util.HashSet;
+
+import javax.crypto.KeyAgreement;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.util.test.SimpleTest;
public class NamedCurveTest
extends SimpleTest
@@ -42,7 +48,7 @@ public class NamedCurveTest
CURVE_NAMES.put("secp224r1", "secp224r1");
CURVE_NAMES.put("B-409", SECNamedCurves.getName(NISTNamedCurves.getOID("B-409"))); // nist
CURVE_NAMES.put("P-521", SECNamedCurves.getName(NISTNamedCurves.getOID("P-521")));
- CURVE_NAMES.put("brainpoolP160r1", "brainpoolP160r1"); // TeleTrusT
+ CURVE_NAMES.put("brainpoolP160r1", "brainpoolp160r1"); // TeleTrusT
CURVE_ALIASES.put("secp192r1", "prime192v1");
CURVE_ALIASES.put("secp256r1", "prime256v1");
@@ -282,6 +288,79 @@ public class NamedCurveTest
}
}
+ public void testAcceptable()
+ throws Exception
+ {
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256");
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
+
+ kpGen.initialize(ecSpec);
+
+ KeyPair kp = kpGen.generateKeyPair();
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded());
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded());
+
+ KeyFactory kf = KeyFactory.getInstance("EC", "BC");
+
+ ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC"));
+
+ bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-384")));
+
+ try
+ {
+ kf.generatePrivate(privSpec);
+ fail("no exception");
+ }
+ catch (InvalidKeySpecException e)
+ {
+ isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage()));
+ }
+
+ try
+ {
+ kf.generatePublic(pubSpec);
+ fail("no exception");
+ }
+ catch (InvalidKeySpecException e)
+ {
+ isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage()));
+ }
+
+ bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-256")));
+
+ kf.generatePrivate(privSpec);
+ kf.generatePublic(pubSpec);
+
+ bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.EMPTY_SET);
+
+ kf.generatePrivate(privSpec);
+ kf.generatePublic(pubSpec);
+ }
+
+ public void testAdditional()
+ throws Exception
+ {
+ ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC"));
+ ASN1ObjectIdentifier bogusCurveID = Extension.auditIdentity;
+
+ bcProv.setParameter(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS, Collections.singletonMap(bogusCurveID, NISTNamedCurves.getByName("P-384")));
+
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
+
+ kpGen.initialize(new ECGenParameterSpec(bogusCurveID.getId()));
+
+ KeyPair kp = kpGen.generateKeyPair();
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded());
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded());
+
+ KeyFactory kf = KeyFactory.getInstance("EC", "BC");
+
+ kf.generatePrivate(privSpec);
+ kf.generatePublic(pubSpec);
+ }
+
public String getName()
{
return "NamedCurve";
@@ -329,6 +408,9 @@ public class NamedCurveTest
{
testECGOST((String)en.nextElement());
}
+
+ testAcceptable();
+ testAdditional();
}
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PBETest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PBETest.java
index 939dd12f..2cc5530b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PBETest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PBETest.java
@@ -1,8 +1,12 @@
package org.bouncycastle.jce.provider.test;
import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
@@ -29,6 +33,7 @@ import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -458,6 +463,25 @@ public class PBETest
}
}
+ public void testNullSalt()
+ throws Exception
+ {
+ SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+ Key key = skf.generateSecret(new PBEKeySpec("secret".toCharArray()));
+
+ Cipher cipher = Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, key, (AlgorithmParameterSpec)null);
+ fail("no exception");
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ isTrue("wrong message", "PBEKey requires parameters to specify salt".equals(e.getMessage()));
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -614,6 +638,9 @@ public class PBETest
testCipherNameWithWrap("PBEWITHSHAAND128BITRC4", "RC4");
checkPBE("PBKDF2WithHmacSHA1", true, "f14687fc31a66e2f7cc01d0a65f687961bd27e20", "6f6579193d6433a3e4600b243bb390674f04a615");
+
+ testMixedKeyTypes();
+ testNullSalt();
}
private void testPKCS12Interop()
@@ -691,6 +718,32 @@ public class PBETest
}
}
+ // for regression testing only - don't try this at home.
+ public void testMixedKeyTypes()
+ throws Exception
+ {
+ String provider = "BC";
+ SecretKeyFactory skf =
+ SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1", provider);
+ PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(), Strings.toByteArray("salt"), 100, 128);
+ SecretKey secretKey = skf.generateSecret(pbeks);
+ PBEParameterSpec paramSpec = new PBEParameterSpec(pbeks.getSalt(), pbeks.getIterationCount());
+
+ // in this case pbeSpec picked up from internal class representing key
+ Cipher cipher =
+ Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC", provider);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ fail("no exception");
+ }
+ catch (InvalidKeyException e)
+ {
+ isTrue("wrong exception", "Algorithm requires a PBE key suitable for PKCS12".equals(e.getMessage()));
+ }
+ }
+
public String getName()
{
return "PBETest";
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PSSTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PSSTest.java
index 44d18abd..a27863dc 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PSSTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/PSSTest.java
@@ -20,8 +20,8 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.test.FixedSecureRandom;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestRandomData;
public class PSSTest
extends SimpleTest
@@ -148,6 +148,16 @@ public class PSSTest
fail("PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig)));
}
+ AlgorithmParameters pParams = AlgorithmParameters.getInstance("PSS", "BC");
+
+ pParams.init(pss.getEncoded());
+
+ PSSParameterSpec spec = (PSSParameterSpec)pParams.getParameterSpec(PSSParameterSpec.class);
+
+ isTrue("Digest mismatch", "SHA-256".equals(spec.getDigestAlgorithm()));
+ isTrue("MGF alg mismatch", PSSParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm()));
+ isTrue("MGF Digest mismatch", "SHA-256".equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm()));
+
s = Signature.getInstance("SHA256withRSAandMGF1", "BC");
s.setParameter(pss.getParameterSpec(PSSParameterSpec.class));
@@ -177,6 +187,16 @@ public class PSSTest
fail("PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig)));
}
+ pParams = AlgorithmParameters.getInstance("PSS", "BC");
+
+ pParams.init(pss.getEncoded());
+
+ spec = (PSSParameterSpec)pParams.getParameterSpec(PSSParameterSpec.class);
+
+ isTrue("Digest mismatch", "SHA-512".equals(spec.getDigestAlgorithm()));
+ isTrue("MGF alg mismatch", PSSParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm()));
+ isTrue("MGF Digest mismatch", "SHA-512".equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm()));
+
s = Signature.getInstance("SHA512withRSAandMGF1", "BC");
s.setParameter(pss.getParameterSpec(PSSParameterSpec.class));
@@ -216,7 +236,7 @@ public class PSSTest
byte[] fixedRandomBytes = new byte[saltLen];
random.nextBytes(fixedRandomBytes);
- normalSig.initSign(privKey, new FixedSecureRandom(fixedRandomBytes));
+ normalSig.initSign(privKey, new TestRandomData(fixedRandomBytes));
normalSig.update(sampleMessage);
byte[] normalResult = normalSig.sign();
@@ -228,7 +248,7 @@ public class PSSTest
// Need to init the params explicitly to avoid having a 'raw' variety of every PSS algorithm
rawSig.setParameter(spec);
- rawSig.initSign(privKey, new FixedSecureRandom(fixedRandomBytes));
+ rawSig.initSign(privKey, new TestRandomData(fixedRandomBytes));
rawSig.update(hash);
byte[] rawResult = rawSig.sign();
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/Poly1305Test.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/Poly1305Test.java
index 7bf0eadc..798f1648 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/Poly1305Test.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/Poly1305Test.java
@@ -23,7 +23,7 @@ public class Poly1305Test
extends SimpleTest
{
private static final byte[] MASTER_KEY = Hex
- .decode("95cc0e44d0b79a8856afcae1bec4fe3c01bcb20bfc8b6e03609ddd09f44b060f");
+ .decode("01bcb20bfc8b6e03609ddd09f44b060f"+"95cc0e44d0b79a8856afcae1bec4fe3c");
public String getName()
{
@@ -33,6 +33,7 @@ public class Poly1305Test
public void performTest()
throws Exception
{
+ checkRawPoly1305();
checkRegistrations();
}
@@ -98,6 +99,38 @@ public class Poly1305Test
}
}
+ private void checkRawPoly1305()
+ throws Exception
+ {
+ checkMac("Poly1305", "e8bd1466eaf442dd71598370c1e34392");
+ }
+
+ private void checkMac(String name, String macOutput)
+ throws Exception
+ {
+ KeyGenerator kg = KeyGenerator.getInstance(name);
+ SecretKey key = kg.generateKey();
+
+ try
+ {
+ Poly1305KeyGenerator.checkKey(key.getEncoded());
+ }
+ catch (IllegalArgumentException e)
+ {
+ fail("Generated key for algo " + name + " does not match required Poly1305 format.");
+ }
+
+ Mac mac = Mac.getInstance(name);
+ mac.init(new SecretKeySpec(MASTER_KEY, name));
+ mac.update(new byte[128]);
+ byte[] bytes = mac.doFinal();
+
+ if (!Arrays.areEqual(bytes, Hex.decode(macOutput)))
+ {
+ fail("wrong mac value computed for " + name, macOutput, new String(Hex.encode(bytes)));
+ }
+ }
+
private void checkMac(String name, List missingMacs, List missingKeyGens, String macOutput)
{
try
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RSATest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RSATest.java
index ba138ec5..bb302233 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RSATest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RSATest.java
@@ -26,6 +26,7 @@ import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
@@ -704,6 +705,112 @@ public class RSATest
c.init(Cipher.ENCRYPT_MODE, pubKey, rand);
out = c.update(new byte[40]);
+
+ testGetExceptionsPKCS1();
+ zeroMessageTest();
+
+ oaepDigestCheck("SHA3-224", NISTObjectIdentifiers.id_sha3_224, pub2048Key, priv2048Key, rand, Hex.decode("2aa7812d4f7b7766f8625feb58481ef5b5fa6dfafbea543e4bbba89d6708f4900fc9fd55d5c2b83fefefc67e2ba7a4222217efaa9b9d31920bdcd78733319aca910dfd118aae5e901a6d27a56e37b1a6f86e7404f82da248e77845e58b789f10a1af8a1208f77dda384692609339346c4ea57928b890042e7d70b1d5817f8978dcbc9cd2fcdde37a0a41a52dbef701ddc859a5d58efd10aa5bd8d205c10154db906540bf20dedcff721df11a456df201cb9cbbd092a89a1eb3f11e7e34003d7070e02c8db54e5498e7ee262fb9178f5eb85d1db66baafe0a66e8283df9c41bded218e5d906d28f08803deb3cbd1a92777d55fe56ff022a47f673cac2ca145973"));
+ oaepDigestCheck("SHA3-256", NISTObjectIdentifiers.id_sha3_256, pub2048Key, priv2048Key, rand, Hex.decode("4460e68586ac0ca1832274919c6b9159d40ea1d383a32ca28f0e1a81962289c8c904fa117d90afd7bfefa51b6889d2d999efb72bafd4beb5594bb08f62532ecb077e4968f43e70673341e60649ed64ac49cf1a2396a64577767d8958217a251938a7ac1bbc1aec9c9197a2eb9a375c74a01097fe3717c8bde04f8a20df85ef10a59070970a4a6470131654cecb641d46e464f17ddfe7e0595025bf25f025edbd56b19487cfc87de1642ca5190f289cf78e2c4b1cf90e73ffae331581c23febcf490c32299f2e5bd5a354a0cc996cc692b5a318777d17e734b3c487ad615df7af0fc361af564e6970ee0aa9b140634cdcf1eda91d1a1156326caaa608c4d43ee4"));
+ oaepDigestCheck("SHA3-384", NISTObjectIdentifiers.id_sha3_384, pub2048Key, priv2048Key, rand, Hex.decode("1b9f490569bddac8ea77e3bec8d6d38b159cb88545de86065dbc8757b35fdeb0cce90eaf93ec6d69d691c590fc3feec9974b80e0c0068929c77533be2066b4002ad6d195e473f72e8581255b8d2dfff016ff27ed50e6d3e63cfaf50851b2d43833eea8dab3b4506f517875659099815a96be6e8fd2dc1417c6e3ffadcfd3f494a5544267688d114d3eeaf43ea954686656afb7a3dc2f8a4cdc5d7b90a97acbbe32ff17b3d26d7eb2a4fbc847d49cc8cb8f837646613d1b5a78096cf3f48acf4be95205e0c4cb283447029eae1442fe3813a017604dfd59a9e841473f4d8914860f785fb2194b21cba47cd401bc32720f3df373e59336c3d64c61babd474b4bbe"));
+ oaepDigestCheck("SHA3-512", NISTObjectIdentifiers.id_sha3_512, pub2048Key, priv2048Key, rand, Hex.decode("7b7870bb5ae52276a8b06b59f7321043afb1fa4e5dbca9f14bcce9efaacded531f090646ab0f8701b012cc93c51e0a8591043e6457cde1950f4ffc8ad87d946622ea48a70f95f40c22d88679eb92c10c19db487fd64857d723daf4ccfe749fdd05e6c0be28de57e09d3b5a0981322b6cc7a9743a50eec355a7af5bdcdcddc5e279ad90f599b68c47fdb39916c7a597cf989169e8667fd8602e88c9c128085d0e158ea75eeb37919a91cdf3f2cd5394adaadc4a2f25a6222d2637cb464841dc5820e54843495cb97af6b19edc72f137123813f5d78503232f79e4f617be3a9f09b0206634a2ecfe457dbd71d2d3d8e3dbca486e75e543f559dcea3112ad50a21d"));
+ }
+
+ public void oaepDigestCheck(String digest, ASN1ObjectIdentifier oid, PublicKey pubKey, PrivateKey privKey, SecureRandom rand, byte[] expected)
+ throws Exception
+ {
+ byte[] input = new byte[]
+ {(byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a};
+
+ Cipher c = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC");
+
+ c.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(digest), PSource.PSpecified.DEFAULT), rand);
+
+ byte[] out = c.doFinal(input);
+
+ isTrue("OAEP decrypt failed", Arrays.areEqual(expected, out));
+
+ AlgorithmParameters oaepP = c.getParameters();
+
+ if (!areEqual(oaepP.getEncoded(),
+ new RSAESOAEPparams(
+ new AlgorithmIdentifier(oid, DERNull.INSTANCE),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(oid, DERNull.INSTANCE)),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded()))
+ {
+ fail("OAEP test failed changed parameters for " + digest);
+ }
+
+ c = Cipher.getInstance("RSA/NONE/OAEPWith" + digest + "AndMGF1Padding", "BC");
+
+ c.init(Cipher.DECRYPT_MODE, privKey);
+
+ byte[] dec = c.doFinal(out);
+
+ isTrue("OAEP decrypt failed", Arrays.areEqual(input, dec));
+
+ AlgorithmParameters parameters = AlgorithmParameters.getInstance("OAEP", "BC");
+
+ parameters.init(oaepP.getEncoded());
+
+ OAEPParameterSpec spec = (OAEPParameterSpec)parameters.getParameterSpec(OAEPParameterSpec.class);
+
+ isTrue("Digest mismatch", digest.equals(spec.getDigestAlgorithm()));
+ isTrue("MGF alg mismatch", OAEPParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm()));
+ isTrue("MGF Digest mismatch", digest.equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm()));
+
+ }
+
+ public void testGetExceptionsPKCS1()
+ throws Exception
+ {
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA", "BC");
+ keygen.initialize(1024);
+ KeyPair keypair = keygen.genKeyPair();
+ SecureRandom rand = new SecureRandom();
+ Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
+ byte[] ciphertext = new byte[1024 / 8];
+ HashSet<String> exceptions = new HashSet<String>();
+ final int SAMPLES = 1000;
+ for (int i = 0; i < SAMPLES; i++)
+ {
+ rand.nextBytes(ciphertext);
+ ciphertext[0] = (byte)0;
+ try
+ {
+ c.init(Cipher.DECRYPT_MODE, keypair.getPrivate());
+ c.doFinal(ciphertext);
+ }
+ catch (Exception ex)
+ {
+ String message = ex.toString();
+ exceptions.add(message);
+ }
+ }
+ isTrue("exception count wrong", 1 == exceptions.size());
+ }
+
+ public void zeroMessageTest()
+ throws Exception
+ {
+ KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA", "BC");
+
+ RSAKeyGenParameterSpec rsaSpec = new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4);
+
+ kgen.initialize(rsaSpec);
+
+ KeyPair kp = kgen.generateKeyPair();
+
+ byte[] plain = new byte[0];
+
+ Cipher rsaCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC");
+ rsaCipher.init(Cipher.ENCRYPT_MODE, kp.getPublic());
+ byte[] encrypted = rsaCipher.doFinal(plain);
+
+ rsaCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC");
+ rsaCipher.init(Cipher.DECRYPT_MODE, kp.getPrivate());
+ byte[] decrypted = rsaCipher.doFinal(encrypted);
+
+ isTrue("zero mismatch", Arrays.areEqual(plain, decrypted));
}
private void oaepCompatibilityTest(String digest, PrivateKey privKey, PublicKey pubKey)
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RegressionTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RegressionTest.java
index 216b954f..5c91909b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RegressionTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/RegressionTest.java
@@ -78,7 +78,9 @@ public class RegressionTest
new Shacal2Test(),
new DetDSATest(),
new ThreefishTest(),
- new SM4Test()
+ new SM4Test(),
+ new TLSKDFTest(),
+ new BCFKSStoreTest()
};
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigNameTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigNameTest.java
index 19f9e6db..f86bd687 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigNameTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigNameTest.java
@@ -28,6 +28,12 @@ public class SigNameTest
checkName("SHA256withRSA");
checkName("SHA384withRSA");
checkName("SHA512withRSA");
+
+ checkName("SHA3-224withRSA");
+ checkName("SHA3-256withRSA");
+ checkName("SHA3-384withRSA");
+ checkName("SHA3-512withRSA");
+
checkName("MD2withRSA");
checkName("MD4withRSA");
checkName("MD5withRSA");
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigTest.java
index af9a8f5e..102c1f7d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/SigTest.java
@@ -21,6 +21,10 @@ import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.DigestInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
@@ -193,86 +197,6 @@ public class SigTest
}
//
- // SHA-224
- //
- sig = Signature.getInstance("SHA224WithRSAEncryption", "BC");
-
- sig.initSign(signingKey);
-
- sig.update(data);
-
- sigBytes = sig.sign();
-
- sig.initVerify(verifyKey);
-
- sig.update(data);
-
- if (!sig.verify(sigBytes))
- {
- fail("SHA224 verification failed");
- }
-
- //
- // SHA-256
- //
- sig = Signature.getInstance("SHA256WithRSAEncryption", "BC");
-
- sig.initSign(signingKey);
-
- sig.update(data);
-
- sigBytes = sig.sign();
-
- sig.initVerify(verifyKey);
-
- sig.update(data);
-
- if (!sig.verify(sigBytes))
- {
- fail("SHA256 verification failed");
- }
-
- //
- // SHA-384
- //
- sig = Signature.getInstance("SHA384WithRSAEncryption", "BC");
-
- sig.initSign(signingKey);
-
- sig.update(data);
-
- sigBytes = sig.sign();
-
- sig.initVerify(verifyKey);
-
- sig.update(data);
-
- if (!sig.verify(sigBytes))
- {
- fail("SHA384 verification failed");
- }
-
- //
- // SHA-512
- //
- sig = Signature.getInstance("SHA512WithRSAEncryption", "BC");
-
- sig.initSign(signingKey);
-
- sig.update(data);
-
- sigBytes = sig.sign();
-
- sig.initVerify(verifyKey);
-
- sig.update(data);
-
- if (!sig.verify(sigBytes))
- {
- fail("SHA512 verification failed");
- }
-
- //
// ISO Sigs.
//
sig = Signature.getInstance("MD5WithRSA/ISO9796-2", "BC");
@@ -309,8 +233,27 @@ public class SigTest
fail("SHA1/ISO verification failed");
}
- trySig("SHA512(224)WithRSA", data, signingKey, verifyKey);
- trySig("SHA512(256)WithRSA", data, signingKey, verifyKey);
+ tryRsaPkcs15Sig("SHA224WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ tryRsaPkcs15Sig("SHA256WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ tryRsaPkcs15Sig("SHA384WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ tryRsaPkcs15Sig("SHA512WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ tryRsaPkcs15Sig("SHA512(224)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224);
+ tryRsaPkcs15Sig("SHA512(256)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256);
+ tryRsaPkcs15Sig("SHA224WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ tryRsaPkcs15Sig("SHA256WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ tryRsaPkcs15Sig("SHA384WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ tryRsaPkcs15Sig("SHA512WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ tryRsaPkcs15Sig("SHA512(224)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224);
+ tryRsaPkcs15Sig("SHA512(256)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256);
+
+ tryRsaPkcs15Sig("SHA3-224WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224);
+ tryRsaPkcs15Sig("SHA3-256WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256);
+ tryRsaPkcs15Sig("SHA3-384WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384);
+ tryRsaPkcs15Sig("SHA3-512WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512);
+ tryRsaPkcs15Sig("SHA3-224WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224);
+ tryRsaPkcs15Sig("SHA3-256WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256);
+ tryRsaPkcs15Sig("SHA3-384WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384);
+ tryRsaPkcs15Sig("SHA3-512WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512);
trySig("SHA1WithRSAAndMGF1", data, signingKey, verifyKey);
trySig("SHA224WithRSAAndMGF1", data, signingKey, verifyKey);
@@ -320,6 +263,11 @@ public class SigTest
trySig("SHA512(224)WithRSAAndMGF1", data, signingKey, verifyKey);
trySig("SHA512(256)WithRSAAndMGF1", data, signingKey, verifyKey);
+ trySig("SHA3-224WithRSAAndMGF1", data, signingKey, verifyKey);
+ trySig("SHA3-256WithRSAAndMGF1", data, signingKey, verifyKey);
+// trySig("SHA3-384WithRSAAndMGF1", data, signingKey, verifyKey);
+// trySig("SHA3-512WithRSAAndMGF1", data, signingKey, verifyKey);
+
trySig("SHA1WithRSA/ISO9796-2", data, signingKey, verifyKey);
trySig("SHA224WithRSA/ISO9796-2", data, signingKey, verifyKey);
trySig("SHA256withRSA/ISO9796-2", data, signingKey, verifyKey);
@@ -415,6 +363,54 @@ public class SigTest
}
}
+ private void tryRsaPkcs15Sig(String algorithm, byte[] data, PrivateKey signingKey, PublicKey verifyKey, ASN1ObjectIdentifier sigOid, ASN1ObjectIdentifier hashOid)
+ throws Exception
+ {
+ Signature sig;
+ byte[] sigBytes;
+ sig = Signature.getInstance(algorithm, "BC");
+
+ sig.initSign(signingKey);
+
+ sig.update(data);
+
+ sigBytes = sig.sign();
+
+ sig.initVerify(verifyKey);
+
+ sig.update(data);
+
+ if (!sig.verify(sigBytes))
+ {
+ fail(algorithm + " verification failed");
+ }
+
+ Cipher c = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC");
+
+ c.init(Cipher.DECRYPT_MODE, verifyKey);
+
+ DigestInfo digInfo = DigestInfo.getInstance(c.doFinal(sigBytes));
+
+ isTrue("digest alg not match", digInfo.getAlgorithmId().getAlgorithm().equals(hashOid));
+
+ sig = Signature.getInstance(sigOid.getId(), "BC");
+
+ sig.initSign(signingKey);
+
+ sig.update(data);
+
+ isTrue("sig not matched", Arrays.areEqual(sigBytes, sig.sign()));
+
+ sig.initVerify(verifyKey);
+
+ sig.update(data);
+
+ if (!sig.verify(sigBytes))
+ {
+ fail(algorithm + " oid verification failed");
+ }
+ }
+
private void shouldPassSignatureX931Test1()
throws Exception
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TLSKDFTest.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TLSKDFTest.java
new file mode 100644
index 00000000..35e99bbf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TLSKDFTest.java
@@ -0,0 +1,159 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.Security;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+
+import org.bouncycastle.jcajce.spec.TLSKeyMaterialSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class TLSKDFTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "TLSKDF";
+ }
+
+ private void testTls10()
+ throws Exception
+ {
+ byte[] pre_master_secret = Hex.decode("bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0");
+ byte[] serverHello_random = Hex.decode("135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2");
+ byte[] clientHello_random = Hex.decode("e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693");
+ byte[] server_random = Hex.decode("67267e650eb32444119d222a368c191af3082888dc35afe8368e638c828874be");
+ byte[] client_random = Hex.decode("d58a7b1cd4fedaa232159df652ce188f9d997e061b9bf48e83b62990440931f6");
+ byte[] master_secret = Hex.decode("2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62");
+ byte[] key_block = Hex.decode("3088825988e77fce68d19f756e18e43eb7fe672433504feaf99b3c503d9091b164f166db301d70c9fc0870b4a94563907bee1a61fb786cb717576890bcc51cb9ead97e01d0a2fea99c953377b195205ff07b369589178796edc963fd80fdbe518a2fc1c35c18ae8d");
+
+ SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS10KDF", "BC");
+
+ SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random));
+
+ isTrue("name mismatch (10): " + keyMaterial.getAlgorithm(), keyMaterial.getAlgorithm().equals("TLS10KDF"));
+
+ isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded()));
+
+ keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random));
+
+ isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded()));
+ }
+
+ private void testTls11()
+ throws Exception
+ {
+ byte[] pre_master_secret = Hex.decode("bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0");
+ byte[] serverHello_random = Hex.decode("135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2");
+ byte[] clientHello_random = Hex.decode("e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693");
+ byte[] server_random = Hex.decode("67267e650eb32444119d222a368c191af3082888dc35afe8368e638c828874be");
+ byte[] client_random = Hex.decode("d58a7b1cd4fedaa232159df652ce188f9d997e061b9bf48e83b62990440931f6");
+ byte[] master_secret = Hex.decode("2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62");
+ byte[] key_block = Hex.decode("3088825988e77fce68d19f756e18e43eb7fe672433504feaf99b3c503d9091b164f166db301d70c9fc0870b4a94563907bee1a61fb786cb717576890bcc51cb9ead97e01d0a2fea99c953377b195205ff07b369589178796edc963fd80fdbe518a2fc1c35c18ae8d");
+
+ SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS11KDF", "BC");
+
+ SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random));
+
+ isTrue("name mismatch (11): " + keyMaterial.getAlgorithm(), keyMaterial.getAlgorithm().equals("TLS11KDF"));
+
+ isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded()));
+
+ keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random));
+
+ isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded()));
+ }
+
+ private void testTls12Sha256()
+ throws Exception
+ {
+ byte[] pre_master_secret = Hex.decode("f8938ecc9edebc5030c0c6a441e213cd24e6f770a50dda07876f8d55da062bcadb386b411fd4fe4313a604fce6c17fbc");
+ byte[] serverHello_random = Hex.decode("f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce");
+ byte[] clientHello_random = Hex.decode("36c129d01a3200894b9179faac589d9835d58775f9b5ea3587cb8fd0364cae8c");
+ byte[] server_random = Hex.decode("ae6c806f8ad4d80784549dff28a4b58fd837681a51d928c3e30ee5ff14f39868");
+ byte[] client_random = Hex.decode("62e1fd91f23f558a605f28478c58cf72637b89784d959df7e946d3f07bd1b616");
+ byte[] master_secret = Hex.decode("202c88c00f84a17a20027079604787461176455539e705be730890602c289a5001e34eeb3a043e5d52a65e66125188bf");
+ byte[] key_block = Hex.decode("d06139889fffac1e3a71865f504aa5d0d2a2e89506c6f2279b670c3e1b74f531016a2530c51a3a0f7e1d6590d0f0566b2f387f8d11fd4f731cdd572d2eae927f6f2f81410b25e6960be68985add6c38445ad9f8c64bf8068bf9a6679485d966f1ad6f68b43495b10a683755ea2b858d70ccac7ec8b053c6bd41ca299d4e51928");
+
+ SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA256KDF", "BC");
+
+ SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random));
+
+ isTrue("name mismatch (12-256)", keyMaterial.getAlgorithm().equals("TLS12withSHA256KDF"));
+
+ isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded()));
+
+ keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random));
+
+ isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded()));
+ }
+
+ private void testTls12Sha384()
+ throws Exception
+ {
+ byte[] pre_master_secret = Hex.decode("a5e2642633f5b8c81ad3fe0c2fe3a8e5ef806b06121dd10df4bb0fe857bfdcf522558e05d2682c9a80c741a3aab1716f");
+ byte[] serverHello_random = Hex.decode("cb6e0b3eb02976b6466dfa9651c2919414f1648fd3a7838d02153e5bd39535b6");
+ byte[] clientHello_random = Hex.decode("abe4bf5527429ac8eb13574d2709e8012bd1a113c6d3b1d3aa2c3840518778ac");
+ byte[] server_random = Hex.decode("1b1c8568344a65c30828e7483c0e353e2c68641c9551efae6927d9cd627a107c");
+ byte[] client_random = Hex.decode("954b5fe1849c2ede177438261f099a2fcd884d001b9fe1de754364b1f6a6dd8e");
+ byte[] master_secret = Hex.decode("b4d49bfa87747fe815457bc3da15073d6ac73389e703079a3503c09e14bd559a5b3c7c601c7365f6ea8c68d3d9596827");
+ byte[] key_block = Hex.decode("10fd89ef689c7ef033387b8a8f3e5e8e7c11f680f6bdd71fbac3246a73e98d45d03185dde686e6b2369e4503e9dc5a6d2cee3e2bf2fa3f41d3de57dff3e197c8a9d5f74cc2d277119d894f8584b07a0a5822f0bd68b3433ec6adaf5c9406c5f3ddbb71bbe17ce98f3d4d5893d3179ef369f57aad908e2bf710639100c3ce7e0c");
+
+ SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA384KDF", "BC");
+
+ SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random));
+
+ isTrue("name mismatch (12-384)", keyMaterial.getAlgorithm().equals("TLS12withSHA384KDF"));
+
+ isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded()));
+
+ keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random));
+
+ isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded()));
+ }
+
+ private void testTls12Sha512()
+ throws Exception
+ {
+ byte[] pre_master_secret = Hex.decode("dfef39af25c12663a91ee5d27042b9644a16ef55b81055d1bd7dcb0b8f06eb001708cdefcf82591defca1a6f1ac693ab");
+ byte[] serverHello_random = Hex.decode("e2339a6c681eb30808883971b1ce5b9b1ece0f3d011a96a7fff1f5f9d80ffd4b");
+ byte[] clientHello_random = Hex.decode("78bc5298dfe9cf8ed336c2e2f0f6b46e2456f39f35f1143cd21eaa16277025b2");
+ byte[] server_random = Hex.decode("11cfbd3b45e5e917c4edbabc27b9feac833bbbacabd079465b2759fab3063330");
+ byte[] client_random = Hex.decode("b5c41ac5ebd55d136d916547fee741bc1b509f766d50b29d7378b0cebace3c8a");
+ byte[] master_secret = Hex.decode("a70c5fe8d34b645a20ce98969bd30858e729c77c8a5f05d3e289219d6b5752b75b75e1ca00d3329658d7f188ed1ab7e0");
+ byte[] key_block = Hex.decode("a56650076e6bdaad7e1ea42d68a0f5ffead9b6b5232ba538767e4cc6a3ae9abcae897b068645496cd620f865ce0879081a98901fb98b112ce1f00165e7d6b3288eb4d4ed9811fdbbc24e290b8e448c71da72498449ea67cfdafd66adc31a89d83cc44cf01c749fb531494ff8cb9a677762a7220e32b7f251fde09841bf97110e");
+
+ SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA512KDF", "BC");
+
+ SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random));
+
+ isTrue("name mismatch (12-512)", keyMaterial.getAlgorithm().equals("TLS12withSHA512KDF"));
+
+ isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded()));
+
+ keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random));
+
+ isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded()));
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testTls10();
+ testTls11();
+ testTls12Sha256();
+ testTls12Sha384();
+ testTls12Sha512();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new TLSKDFTest());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TestUtils.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TestUtils.java
index 768c926b..31537b8f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TestUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/test/TestUtils.java
@@ -53,6 +53,7 @@ import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.jce.PrincipalUtil;
@@ -72,6 +73,8 @@ class TestUtils
algIds.put("GOST3411withGOST3410", new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94));
algIds.put("SHA1withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE));
algIds.put("SHA256withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE));
+ algIds.put("SHA1withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA1));
+ algIds.put("SHA256withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256));
}
public static X509Certificate createSelfSignedCert(String dn, String sigName, KeyPair keyPair)
@@ -257,6 +260,18 @@ class TestUtils
return new ExceptionCertificate(exceptionOnEncode);
}
+ public static X500Name getCertIssuer(X509Certificate x509Certificate)
+ throws CertificateEncodingException
+ {
+ return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getIssuer();
+ }
+
+ public static X500Name getCertSubject(X509Certificate x509Certificate)
+ throws CertificateEncodingException
+ {
+ return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getSubject();
+ }
+
private static class ExceptionCertificate
extends X509Certificate
{
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java
index c18a88fd..cc29c106 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java
@@ -33,24 +33,6 @@ public class IESParameterSpec
this(derivation, encoding, macKeySize, -1, null, false);
}
-
- /**
- * Set the IES engine parameters.
- *
- * @param derivation the optional derivation vector for the KDF.
- * @param encoding the optional encoding vector for the KDF.
- * @param macKeySize the key size (in bits) for the MAC.
- * @param cipherKeySize the key size (in bits) for the block cipher.
- */
- public IESParameterSpec(
- byte[] derivation,
- byte[] encoding,
- int macKeySize,
- int cipherKeySize)
- {
- this(derivation, encoding, macKeySize, cipherKeySize, null, false);
- }
-
/**
* Set the IES engine parameters.
*
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
index 339689ea..301b5aee 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
@@ -440,7 +440,7 @@ public abstract class WNafUtil
* 1) additions do not use the curve's A, B coefficients.
* 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
*/
- if (ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64)
+ if (!twiceP.isInfinity() && ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64)
{
switch (c.getCoordinateSystem())
{
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
index 5a066d81..1e04f4b9 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
@@ -112,9 +112,10 @@ public class SecP256R1Field
long t4 = xx12 + xx13;
long t5 = xx13 + xx14;
long t6 = xx14 + xx15;
+ long t7 = t5 - t0;
long cc = 0;
- cc += (xx[0] & M) + t0 - t3 - t5;
+ cc += (xx[0] & M) - t3 - t7;
z[0] = (int)cc;
cc >>= 32;
cc += (xx[1] & M) + t1 - t4 - t6;
@@ -123,7 +124,7 @@ public class SecP256R1Field
cc += (xx[2] & M) + t2 - t5;
z[2] = (int)cc;
cc >>= 32;
- cc += (xx[3] & M) + (t3 << 1) + xx13 - xx15 - t0;
+ cc += (xx[3] & M) + (t3 << 1) + t7 - t6;
z[3] = (int)cc;
cc >>= 32;
cc += (xx[4] & M) + (t4 << 1) + xx14 - t1;
@@ -132,7 +133,7 @@ public class SecP256R1Field
cc += (xx[5] & M) + (t5 << 1) - t2;
z[5] = (int)cc;
cc >>= 32;
- cc += (xx[6] & M) + (t6 << 1) + t5 - t0;
+ cc += (xx[6] & M) + (t6 << 1) + t7;
z[6] = (int)cc;
cc >>= 32;
cc += (xx[7] & M) + (xx15 << 1) + xx08 - t2 - t4;
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
index fcbb8727..164a7957 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
@@ -107,9 +107,10 @@ public class SecP384R1Field
long t4 = xx17 + xx21;
long t5 = xx21 - xx23;
long t6 = xx22 - xx23;
+ long t7 = t0 + t5;
long cc = 0;
- cc += (xx[0] & M) + t0 + t5;
+ cc += (xx[0] & M) + t7;
z[0] = (int)cc;
cc >>= 32;
cc += (xx[1] & M) + xx23 - t0 + t1;
@@ -118,10 +119,10 @@ public class SecP384R1Field
cc += (xx[2] & M) - xx21 - t1 + t2;
z[2] = (int)cc;
cc >>= 32;
- cc += (xx[3] & M) + t0 - t2 + t3 + t5;
+ cc += (xx[3] & M) - t2 + t3 + t7;
z[3] = (int)cc;
cc >>= 32;
- cc += (xx[4] & M) + xx16 + xx21 + t0 + t1 - t3 + t5;
+ cc += (xx[4] & M) + xx16 + xx21 + t1 - t3 + t7;
z[4] = (int)cc;
cc >>= 32;
cc += (xx[5] & M) - xx16 + t1 + t2 + t4;
diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat128.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat128.java
index 8d621c17..ae4ae489 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat128.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat128.java
@@ -636,8 +636,8 @@ public abstract class Nat128
}
long x_3 = x[3] & M;
- long zz_5 = zz[5] & M;
- long zz_6 = zz[6] & M;
+ long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -658,7 +658,7 @@ public abstract class Nat128
w = (int)zz_6;
zz[6] = (w << 1) | c;
c = w >>> 31;
- w = zz[7] + (int)(zz_6 >> 32);
+ w = zz[7] + (int)(zz_6 >>> 32);
zz[7] = (w << 1) | c;
}
@@ -713,8 +713,8 @@ public abstract class Nat128
}
long x_3 = x[xOff + 3] & M;
- long zz_5 = zz[zzOff + 5] & M;
- long zz_6 = zz[zzOff + 6] & M;
+ long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -734,7 +734,7 @@ public abstract class Nat128
w = (int)zz_6;
zz[zzOff + 6] = (w << 1) | c;
c = w >>> 31;
- w = zz[zzOff + 7] + (int)(zz_6 >> 32);
+ w = zz[zzOff + 7] + (int)(zz_6 >>> 32);
zz[zzOff + 7] = (w << 1) | c;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat160.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat160.java
index 55010dc3..620f9bcf 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat160.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat160.java
@@ -609,8 +609,8 @@ public abstract class Nat160
}
long x_3 = x[3] & M;
- long zz_5 = zz[5] & M;
- long zz_6 = zz[6] & M;
+ long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -624,8 +624,8 @@ public abstract class Nat160
}
long x_4 = x[4] & M;
- long zz_7 = zz[7] & M;
- long zz_8 = zz[8] & M;
+ long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -649,7 +649,7 @@ public abstract class Nat160
w = (int)zz_8;
zz[8] = (w << 1) | c;
c = w >>> 31;
- w = zz[9] + (int)(zz_8 >> 32);
+ w = zz[9] + (int)(zz_8 >>> 32);
zz[9] = (w << 1) | c;
}
@@ -704,8 +704,8 @@ public abstract class Nat160
}
long x_3 = x[xOff + 3] & M;
- long zz_5 = zz[zzOff + 5] & M;
- long zz_6 = zz[zzOff + 6] & M;
+ long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -719,8 +719,8 @@ public abstract class Nat160
}
long x_4 = x[xOff + 4] & M;
- long zz_7 = zz[zzOff + 7] & M;
- long zz_8 = zz[zzOff + 8] & M;
+ long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -744,7 +744,7 @@ public abstract class Nat160
w = (int)zz_8;
zz[zzOff + 8] = (w << 1) | c;
c = w >>> 31;
- w = zz[zzOff + 9] + (int)(zz_8 >> 32);
+ w = zz[zzOff + 9] + (int)(zz_8 >>> 32);
zz[zzOff + 9] = (w << 1) | c;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java
index 421883e0..12db01bc 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java
@@ -715,8 +715,8 @@ public abstract class Nat192
}
long x_3 = x[3] & M;
- long zz_5 = zz[5] & M;
- long zz_6 = zz[6] & M;
+ long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -730,8 +730,8 @@ public abstract class Nat192
}
long x_4 = x[4] & M;
- long zz_7 = zz[7] & M;
- long zz_8 = zz[8] & M;
+ long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -747,8 +747,8 @@ public abstract class Nat192
}
long x_5 = x[5] & M;
- long zz_9 = zz[9] & M;
- long zz_10 = zz[10] & M;
+ long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -776,7 +776,7 @@ public abstract class Nat192
w = (int)zz_10;
zz[10] = (w << 1) | c;
c = w >>> 31;
- w = zz[11] + (int)(zz_10 >> 32);
+ w = zz[11] + (int)(zz_10 >>> 32);
zz[11] = (w << 1) | c;
}
@@ -831,8 +831,8 @@ public abstract class Nat192
}
long x_3 = x[xOff + 3] & M;
- long zz_5 = zz[zzOff + 5] & M;
- long zz_6 = zz[zzOff + 6] & M;
+ long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -846,8 +846,8 @@ public abstract class Nat192
}
long x_4 = x[xOff + 4] & M;
- long zz_7 = zz[zzOff + 7] & M;
- long zz_8 = zz[zzOff + 8] & M;
+ long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -863,8 +863,8 @@ public abstract class Nat192
}
long x_5 = x[xOff + 5] & M;
- long zz_9 = zz[zzOff + 9] & M;
- long zz_10 = zz[zzOff + 10] & M;
+ long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -892,7 +892,7 @@ public abstract class Nat192
w = (int)zz_10;
zz[zzOff + 10] = (w << 1) | c;
c = w >>> 31;
- w = zz[zzOff + 11] + (int)(zz_10 >> 32);
+ w = zz[zzOff + 11] + (int)(zz_10 >>> 32);
zz[zzOff + 11] = (w << 1) | c;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java
index bbe81caa..9ff107c1 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java
@@ -793,8 +793,8 @@ public abstract class Nat224
}
long x_3 = x[3] & M;
- long zz_5 = zz[5] & M;
- long zz_6 = zz[6] & M;
+ long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -808,8 +808,8 @@ public abstract class Nat224
}
long x_4 = x[4] & M;
- long zz_7 = zz[7] & M;
- long zz_8 = zz[8] & M;
+ long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -825,8 +825,8 @@ public abstract class Nat224
}
long x_5 = x[5] & M;
- long zz_9 = zz[9] & M;
- long zz_10 = zz[10] & M;
+ long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -844,8 +844,8 @@ public abstract class Nat224
}
long x_6 = x[6] & M;
- long zz_11 = zz[11] & M;
- long zz_12 = zz[12] & M;
+ long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M;
+ long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (int)zz_6;
@@ -877,7 +877,7 @@ public abstract class Nat224
w = (int)zz_12;
zz[12] = (w << 1) | c;
c = w >>> 31;
- w = zz[13] + (int)(zz_12 >> 32);
+ w = zz[13] + (int)(zz_12 >>> 32);
zz[13] = (w << 1) | c;
}
@@ -932,8 +932,8 @@ public abstract class Nat224
}
long x_3 = x[xOff + 3] & M;
- long zz_5 = zz[zzOff + 5] & M;
- long zz_6 = zz[zzOff + 6] & M;
+ long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -947,8 +947,8 @@ public abstract class Nat224
}
long x_4 = x[xOff + 4] & M;
- long zz_7 = zz[zzOff + 7] & M;
- long zz_8 = zz[zzOff + 8] & M;
+ long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -964,8 +964,8 @@ public abstract class Nat224
}
long x_5 = x[xOff + 5] & M;
- long zz_9 = zz[zzOff + 9] & M;
- long zz_10 = zz[zzOff + 10] & M;
+ long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -983,8 +983,8 @@ public abstract class Nat224
}
long x_6 = x[xOff + 6] & M;
- long zz_11 = zz[zzOff + 11] & M;
- long zz_12 = zz[zzOff + 12] & M;
+ long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M;
+ long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (int)zz_6;
@@ -1016,7 +1016,7 @@ public abstract class Nat224
w = (int)zz_12;
zz[zzOff + 12] = (w << 1) | c;
c = w >>> 31;
- w = zz[zzOff + 13] + (int)(zz_12 >> 32);
+ w = zz[zzOff + 13] + (int)(zz_12 >>> 32);
zz[zzOff + 13] = (w << 1) | c;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java
index db1daac0..726bae35 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java
@@ -926,8 +926,8 @@ public abstract class Nat256
}
long x_3 = x[3] & M;
- long zz_5 = zz[5] & M;
- long zz_6 = zz[6] & M;
+ long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -941,8 +941,8 @@ public abstract class Nat256
}
long x_4 = x[4] & M;
- long zz_7 = zz[7] & M;
- long zz_8 = zz[8] & M;
+ long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -958,8 +958,8 @@ public abstract class Nat256
}
long x_5 = x[5] & M;
- long zz_9 = zz[9] & M;
- long zz_10 = zz[10] & M;
+ long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -977,8 +977,8 @@ public abstract class Nat256
}
long x_6 = x[6] & M;
- long zz_11 = zz[11] & M;
- long zz_12 = zz[12] & M;
+ long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M;
+ long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (int)zz_6;
@@ -998,8 +998,8 @@ public abstract class Nat256
}
long x_7 = x[7] & M;
- long zz_13 = zz[13] & M;
- long zz_14 = zz[14] & M;
+ long zz_13 = (zz[13] & M) + (zz_12 >>> 32); zz_12 &= M;
+ long zz_14 = (zz[14] & M) + (zz_13 >>> 32); zz_13 &= M;
{
zz_7 += x_7 * x_0;
w = (int)zz_7;
@@ -1035,7 +1035,7 @@ public abstract class Nat256
w = (int)zz_14;
zz[14] = (w << 1) | c;
c = w >>> 31;
- w = zz[15] + (int)(zz_14 >> 32);
+ w = zz[15] + (int)(zz_14 >>> 32);
zz[15] = (w << 1) | c;
}
@@ -1090,8 +1090,8 @@ public abstract class Nat256
}
long x_3 = x[xOff + 3] & M;
- long zz_5 = zz[zzOff + 5] & M;
- long zz_6 = zz[zzOff + 6] & M;
+ long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+ long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
{
zz_3 += x_3 * x_0;
w = (int)zz_3;
@@ -1105,8 +1105,8 @@ public abstract class Nat256
}
long x_4 = x[xOff + 4] & M;
- long zz_7 = zz[zzOff + 7] & M;
- long zz_8 = zz[zzOff + 8] & M;
+ long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+ long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
{
zz_4 += x_4 * x_0;
w = (int)zz_4;
@@ -1122,8 +1122,8 @@ public abstract class Nat256
}
long x_5 = x[xOff + 5] & M;
- long zz_9 = zz[zzOff + 9] & M;
- long zz_10 = zz[zzOff + 10] & M;
+ long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+ long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
{
zz_5 += x_5 * x_0;
w = (int)zz_5;
@@ -1141,8 +1141,8 @@ public abstract class Nat256
}
long x_6 = x[xOff + 6] & M;
- long zz_11 = zz[zzOff + 11] & M;
- long zz_12 = zz[zzOff + 12] & M;
+ long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M;
+ long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M;
{
zz_6 += x_6 * x_0;
w = (int)zz_6;
@@ -1162,8 +1162,8 @@ public abstract class Nat256
}
long x_7 = x[xOff + 7] & M;
- long zz_13 = zz[zzOff + 13] & M;
- long zz_14 = zz[zzOff + 14] & M;
+ long zz_13 = (zz[zzOff + 13] & M) + (zz_12 >>> 32); zz_12 &= M;
+ long zz_14 = (zz[zzOff + 14] & M) + (zz_13 >>> 32); zz_13 &= M;
{
zz_7 += x_7 * x_0;
w = (int)zz_7;
@@ -1199,7 +1199,7 @@ public abstract class Nat256
w = (int)zz_14;
zz[zzOff + 14] = (w << 1) | c;
c = w >>> 31;
- w = zz[zzOff + 15] + (int)(zz_14 >> 32);
+ w = zz[zzOff + 15] + (int)(zz_14 >>> 32);
zz[zzOff + 15] = (w << 1) | c;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java
index 192484f8..c3b976bc 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java
@@ -5,77 +5,68 @@ import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-
-import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+/**
+ * Return the keyData to encode in the PrivateKeyInfo structure.
+ * <p>
+ * The ASN.1 definition of the key structure is
+ * <pre>
+ * McElieceCCA2PrivateKey ::= SEQUENCE {
+ * m INTEGER -- extension degree of the field
+ * k INTEGER -- dimension of the code
+ * field OCTET STRING -- field polynomial
+ * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * p OCTET STRING -- permutation vector
+ * digest AlgorithmIdentifier -- algorithm identifier for CCA2 digest
+ * }
+ * </pre>
+ * </p>
+ */
public class McElieceCCA2PrivateKey
extends ASN1Object
{
- private ASN1ObjectIdentifier oid;
private int n;
private int k;
private byte[] encField;
private byte[] encGp;
private byte[] encP;
- private byte[] encH;
- private byte[][] encqInv;
+ private AlgorithmIdentifier digest;
- public McElieceCCA2PrivateKey(ASN1ObjectIdentifier oid, int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ public McElieceCCA2PrivateKey(int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p, AlgorithmIdentifier digest)
{
- this.oid = oid;
this.n = n;
this.k = k;
this.encField = field.getEncoded();
this.encGp = goppaPoly.getEncoded();
this.encP = p.getEncoded();
- this.encH = h.getEncoded();
- this.encqInv = new byte[qInv.length][];
-
- for (int i = 0; i != qInv.length; i++)
- {
- encqInv[i] = qInv[i].getEncoded();
- }
+ this.digest = digest;
}
private McElieceCCA2PrivateKey(ASN1Sequence seq)
{
- oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
-
- BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue();
n = bigN.intValue();
- BigInteger bigK = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ BigInteger bigK = ((ASN1Integer)seq.getObjectAt(1)).getValue();
k = bigK.intValue();
- encField = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
-
- encGp = ((ASN1OctetString)seq.getObjectAt(4)).getOctets();
+ encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets();
- encP = ((ASN1OctetString)seq.getObjectAt(5)).getOctets();
+ encGp = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
- encH = ((ASN1OctetString)seq.getObjectAt(6)).getOctets();
+ encP = ((ASN1OctetString)seq.getObjectAt(4)).getOctets();
- ASN1Sequence asnQInv = (ASN1Sequence)seq.getObjectAt(7);
- encqInv = new byte[asnQInv.size()][];
- for (int i = 0; i < asnQInv.size(); i++)
- {
- encqInv[i] = ((ASN1OctetString)asnQInv.getObjectAt(i)).getOctets();
- }
- }
-
- public ASN1ObjectIdentifier getOID()
- {
- return oid;
+ digest = AlgorithmIdentifier.getInstance(seq.getObjectAt(5));
}
public int getN()
@@ -103,30 +94,16 @@ public class McElieceCCA2PrivateKey
return new Permutation(encP);
}
- public GF2Matrix getH()
+ public AlgorithmIdentifier getDigest()
{
- return new GF2Matrix(encH);
- }
-
- public PolynomialGF2mSmallM[] getQInv()
- {
- PolynomialGF2mSmallM[] qInv = new PolynomialGF2mSmallM[encqInv.length];
- GF2mField field = this.getField();
-
- for (int i = 0; i < encqInv.length; i++)
- {
- qInv[i] = new PolynomialGF2mSmallM(field, encqInv[i]);
- }
-
- return qInv;
+ return digest;
}
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
- // encode <oidString>
- v.add(oid);
+
// encode <n>
v.add(new ASN1Integer(n));
@@ -142,17 +119,7 @@ public class McElieceCCA2PrivateKey
// encode <p>
v.add(new DEROctetString(encP));
- // encode <h>
- v.add(new DEROctetString(encH));
-
- // encode <q>
- ASN1EncodableVector asnQInv = new ASN1EncodableVector();
- for (int i = 0; i < encqInv.length; i++)
- {
- asnQInv.add(new DEROctetString(encqInv[i]));
- }
-
- v.add(new DERSequence(asnQInv));
+ v.add(digest);
return new DERSequence(v);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java
index adb5e46a..918c12e1 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java
@@ -5,46 +5,41 @@ import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
public class McElieceCCA2PublicKey
extends ASN1Object
{
- private ASN1ObjectIdentifier oid;
- private int n;
- private int t;
+ private final int n;
+ private final int t;
+ private final GF2Matrix g;
+ private final AlgorithmIdentifier digest;
- private byte[] matrixG;
-
- public McElieceCCA2PublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g)
+ public McElieceCCA2PublicKey(int n, int t, GF2Matrix g, AlgorithmIdentifier digest)
{
- this.oid = oid;
this.n = n;
this.t = t;
- this.matrixG = g.getEncoded();
+ this.g = new GF2Matrix(g.getEncoded());
+ this.digest = digest;
}
private McElieceCCA2PublicKey(ASN1Sequence seq)
{
- oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
- BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue();
n = bigN.intValue();
- BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ BigInteger bigT = ((ASN1Integer)seq.getObjectAt(1)).getValue();
t = bigT.intValue();
- matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
- }
+ g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets());
- public ASN1ObjectIdentifier getOID()
- {
- return oid;
+ digest = AlgorithmIdentifier.getInstance(seq.getObjectAt(3));
}
public int getN()
@@ -59,14 +54,17 @@ public class McElieceCCA2PublicKey
public GF2Matrix getG()
{
- return new GF2Matrix(matrixG);
+ return g;
+ }
+
+ public AlgorithmIdentifier getDigest()
+ {
+ return digest;
}
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
- // encode <oidString>
- v.add(oid);
// encode <n>
v.add(new ASN1Integer(n));
@@ -75,7 +73,9 @@ public class McElieceCCA2PublicKey
v.add(new ASN1Integer(t));
// encode <matrixG>
- v.add(new DEROctetString(matrixG));
+ v.add(new DEROctetString(g.getEncoded()));
+
+ v.add(digest);
return new DERSequence(v);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java
index 4bf2f822..447e3445 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java
@@ -5,7 +5,6 @@ import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
@@ -19,7 +18,6 @@ import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
public class McEliecePrivateKey
extends ASN1Object
{
- private ASN1ObjectIdentifier oid;
private int n;
private int k;
private byte[] encField;
@@ -27,13 +25,9 @@ public class McEliecePrivateKey
private byte[] encSInv;
private byte[] encP1;
private byte[] encP2;
- private byte[] encH;
- private byte[][] encqInv;
-
- public McEliecePrivateKey(ASN1ObjectIdentifier oid, int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1, Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ public McEliecePrivateKey(int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p1, Permutation p2, GF2Matrix sInv)
{
- this.oid = oid;
this.n = n;
this.k = k;
this.encField = field.getEncoded();
@@ -41,13 +35,6 @@ public class McEliecePrivateKey
this.encSInv = sInv.getEncoded();
this.encP1 = p1.getEncoded();
this.encP2 = p2.getEncoded();
- this.encH = h.getEncoded();
- this.encqInv = new byte[qInv.length][];
-
- for (int i = 0; i != qInv.length; i++)
- {
- encqInv[i] = qInv[i].getEncoded();
- }
}
public static McEliecePrivateKey getInstance(Object o)
@@ -66,38 +53,21 @@ public class McEliecePrivateKey
private McEliecePrivateKey(ASN1Sequence seq)
{
- // <oidString>
- oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
-
- BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue();
n = bigN.intValue();
- BigInteger bigK = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ BigInteger bigK = ((ASN1Integer)seq.getObjectAt(1)).getValue();
k = bigK.intValue();
- encField = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
-
- encGp = ((ASN1OctetString)seq.getObjectAt(4)).getOctets();
-
- encSInv = ((ASN1OctetString)seq.getObjectAt(5)).getOctets();
-
- encP1 = ((ASN1OctetString)seq.getObjectAt(6)).getOctets();
+ encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets();
- encP2 = ((ASN1OctetString)seq.getObjectAt(7)).getOctets();
+ encGp = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
- encH = ((ASN1OctetString)seq.getObjectAt(8)).getOctets();
+ encP1 = ((ASN1OctetString)seq.getObjectAt(4)).getOctets();
- ASN1Sequence asnQInv = (ASN1Sequence)seq.getObjectAt(9);
- encqInv = new byte[asnQInv.size()][];
- for (int i = 0; i < asnQInv.size(); i++)
- {
- encqInv[i] = ((ASN1OctetString)asnQInv.getObjectAt(i)).getOctets();
- }
- }
+ encP2 = ((ASN1OctetString)seq.getObjectAt(5)).getOctets();
- public ASN1ObjectIdentifier getOID()
- {
- return oid;
+ encSInv = ((ASN1OctetString)seq.getObjectAt(6)).getOctets();
}
public int getN()
@@ -135,30 +105,12 @@ public class McEliecePrivateKey
return new Permutation(encP2);
}
- public GF2Matrix getH()
- {
- return new GF2Matrix(encH);
- }
-
- public PolynomialGF2mSmallM[] getQInv()
- {
- PolynomialGF2mSmallM[] qInv = new PolynomialGF2mSmallM[encqInv.length];
- GF2mField field = this.getField();
-
- for (int i = 0; i < encqInv.length; i++)
- {
- qInv[i] = new PolynomialGF2mSmallM(field, encqInv[i]);
- }
-
- return qInv;
- }
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
- // encode <oidString>
- v.add(oid);
+
// encode <n>
v.add(new ASN1Integer(n));
@@ -171,26 +123,14 @@ public class McEliecePrivateKey
// encode <goppaPoly>
v.add(new DEROctetString(encGp));
- // encode <sInv>
- v.add(new DEROctetString(encSInv));
-
// encode <p1>
v.add(new DEROctetString(encP1));
// encode <p2>
v.add(new DEROctetString(encP2));
- // encode <h>
- v.add(new DEROctetString(encH));
-
- // encode <q>
- ASN1EncodableVector asnQInv = new ASN1EncodableVector();
- for (int i = 0; i < encqInv.length; i++)
- {
- asnQInv.add(new DEROctetString(encqInv[i]));
- }
-
- v.add(new DERSequence(asnQInv));
+ // encode <sInv>
+ v.add(new DEROctetString(encSInv));
return new DERSequence(v);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java
index 6f1efc09..0a84365d 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java
@@ -5,7 +5,6 @@ import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
@@ -16,36 +15,26 @@ import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
public class McEliecePublicKey
extends ASN1Object
{
+ private final int n;
+ private final int t;
+ private final GF2Matrix g;
- private ASN1ObjectIdentifier oid;
- private int n;
- private int t;
-
- private byte[] matrixG;
-
- public McEliecePublicKey(ASN1ObjectIdentifier oid, int n, int t, GF2Matrix g)
+ public McEliecePublicKey(int n, int t, GF2Matrix g)
{
- this.oid = oid;
this.n = n;
this.t = t;
- this.matrixG = g.getEncoded();
+ this.g = new GF2Matrix(g);
}
private McEliecePublicKey(ASN1Sequence seq)
{
- oid = ((ASN1ObjectIdentifier)seq.getObjectAt(0));
- BigInteger bigN = ((ASN1Integer)seq.getObjectAt(1)).getValue();
+ BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue();
n = bigN.intValue();
- BigInteger bigT = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ BigInteger bigT = ((ASN1Integer)seq.getObjectAt(1)).getValue();
t = bigT.intValue();
- matrixG = ((ASN1OctetString)seq.getObjectAt(3)).getOctets();
- }
-
- public ASN1ObjectIdentifier getOID()
- {
- return oid;
+ g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets());
}
public int getN()
@@ -60,14 +49,12 @@ public class McEliecePublicKey
public GF2Matrix getG()
{
- return new GF2Matrix(matrixG);
+ return new GF2Matrix(g);
}
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
- // encode <oidString>
- v.add(oid);
// encode <n>
v.add(new ASN1Integer(n));
@@ -76,7 +63,7 @@ public class McEliecePublicKey
v.add(new ASN1Integer(t));
// encode <matrixG>
- v.add(new DEROctetString(matrixG));
+ v.add(new DEROctetString(g.getEncoded()));
return new DERSequence(v);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java
index d93d9952..938d8cfa 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java
@@ -1,6 +1,7 @@
package org.bouncycastle.pqc.asn1;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
/**
* PQC:
@@ -43,4 +44,14 @@ public interface PQCObjectIdentifiers
/** 1.3.6.1.4.1.8301.3.1.3.4.2 */
public static final ASN1ObjectIdentifier mcElieceCca2 = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.2");
+ public static final ASN1ObjectIdentifier mcElieceFujisaki = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.2.1");
+ public static final ASN1ObjectIdentifier mcEliecePointcheval = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.2.2");
+ public static final ASN1ObjectIdentifier mcElieceKobara_Imai = new ASN1ObjectIdentifier("1.3.6.1.4.1.8301.3.1.3.4.2.3");
+
+ public static final ASN1ObjectIdentifier sphincs256 = BCObjectIdentifiers.sphincs256;
+ public static final ASN1ObjectIdentifier sphincs256_with_BLAKE512 = BCObjectIdentifiers.sphincs256_with_BLAKE512;
+ public static final ASN1ObjectIdentifier sphincs256_with_SHA512 = BCObjectIdentifiers.sphincs256_with_SHA512;
+ public static final ASN1ObjectIdentifier sphincs256_with_SHA3_512 = BCObjectIdentifiers.sphincs256_with_SHA3_512;
+
+ public static final ASN1ObjectIdentifier newHope = BCObjectIdentifiers.newHope;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java
new file mode 100644
index 00000000..77f32a3c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.pqc.asn1;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class SPHINCS256KeyParams
+ extends ASN1Object
+{
+ private final ASN1Integer version;
+ private final AlgorithmIdentifier treeDigest;
+
+ public SPHINCS256KeyParams(AlgorithmIdentifier treeDigest)
+ {
+ this.version = new ASN1Integer(0);
+ this.treeDigest = treeDigest;
+ }
+
+ private SPHINCS256KeyParams(ASN1Sequence sequence)
+ {
+ this.version = ASN1Integer.getInstance(sequence.getObjectAt(0));
+ this.treeDigest = AlgorithmIdentifier.getInstance(sequence.getObjectAt(1));
+ }
+
+ public static final SPHINCS256KeyParams getInstance(Object o)
+ {
+ if (o instanceof SPHINCS256KeyParams)
+ {
+ return (SPHINCS256KeyParams)o;
+ }
+ else if (o != null)
+ {
+ return new SPHINCS256KeyParams(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getTreeDigest()
+ {
+ return treeDigest;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(treeDigest);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java
index 6b5b2515..4060e633 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java
@@ -8,7 +8,7 @@ import org.bouncycastle.crypto.params.ParametersWithRandom;
/**
- * Implements the sign and verify functions for a Signature Scheme which can use a hash function.
+ * Implements the sign and verify functions for a Signature Scheme using a hash function to allow processing of large messages.
*/
public class DigestingMessageSigner
implements Signer
@@ -65,7 +65,7 @@ public class DigestingMessageSigner
{
if (!forSigning)
{
- throw new IllegalStateException("RainbowDigestSigner not initialised for signature generation.");
+ throw new IllegalStateException("DigestingMessageSigner not initialised for signature generation.");
}
byte[] hash = new byte[messDigest.getDigestSize()];
@@ -74,27 +74,6 @@ public class DigestingMessageSigner
return messSigner.generateSignature(hash);
}
- /**
- * This function verifies the signature of the message that has been
- * updated, with the aid of the public key.
- *
- * @param signature the signature of the message is given as a byte array.
- * @return true if the signature has been verified, false otherwise.
- */
- public boolean verify(byte[] signature)
- {
- if (forSigning)
- {
- throw new IllegalStateException("RainbowDigestSigner not initialised for verification");
- }
-
- byte[] hash = new byte[messDigest.getDigestSize()];
- messDigest.doFinal(hash, 0);
-
- return messSigner.verifySignature(hash, signature);
-
- }
-
public void update(byte b)
{
messDigest.update(b);
@@ -110,8 +89,23 @@ public class DigestingMessageSigner
messDigest.reset();
}
+ /**
+ * This function verifies the signature of the message that has been
+ * updated, with the aid of the public key.
+ *
+ * @param signature the signature of the message is given as a byte array.
+ * @return true if the signature has been verified, false otherwise.
+ */
public boolean verifySignature(byte[] signature)
{
- return this.verify(signature);
+ if (forSigning)
+ {
+ throw new IllegalStateException("DigestingMessageSigner not initialised for verification");
+ }
+
+ byte[] hash = new byte[messDigest.getDigestSize()];
+ messDigest.doFinal(hash, 0);
+
+ return messSigner.verifySignature(hash, signature);
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePair.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePair.java
new file mode 100644
index 00000000..49f76913
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePair.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.pqc.crypto;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Pair for a value exchange algorithm where the responding party has no private key, such as NewHope.
+ */
+public class ExchangePair
+{
+ private final AsymmetricKeyParameter publicKey;
+ private final byte[] shared;
+
+ /**
+ * Base constructor.
+ *
+ * @param publicKey The responding party's public key.
+ * @param shared the calculated shared value.
+ */
+ public ExchangePair(AsymmetricKeyParameter publicKey, byte[] shared)
+ {
+ this.publicKey = publicKey;
+ this.shared = Arrays.clone(shared);
+ }
+
+ /**
+ * Return the responding party's public key.
+ *
+ * @return the public key calculated for the exchange.
+ */
+ public AsymmetricKeyParameter getPublicKey()
+ {
+ return publicKey;
+ }
+
+ /**
+ * Return the shared value calculated with public key.
+ *
+ * @return the shared value.
+ */
+ public byte[] getSharedValue()
+ {
+ return Arrays.clone(shared);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePairGenerator.java
new file mode 100644
index 00000000..6993899a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ExchangePairGenerator.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.pqc.crypto;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+/**
+ * Interface for NewHope style key material exchange generators.
+ */
+public interface ExchangePairGenerator
+{
+ /**
+ * Generate an exchange pair based on the sender public key.
+ *
+ * @param senderPublicKey the public key of the exchange initiator.
+ * @return An ExchangePair derived from the sender public key.
+ */
+ ExchangePair GenerateExchange(AsymmetricKeyParameter senderPublicKey);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java
index 8d67c5cd..d455d9d0 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java
@@ -2,7 +2,11 @@ package org.bouncycastle.pqc.crypto;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+/**
+ * Base interface for a PQC encryption algorithm.
+ */
public interface MessageEncryptor
{
@@ -19,12 +23,13 @@ public interface MessageEncryptor
* @param message the message to be signed.
* @throws Exception
*/
- public byte[] messageEncrypt(byte[] message) throws Exception;
+ public byte[] messageEncrypt(byte[] message);
/**
*
* @param cipher the cipher text of the message
* @throws Exception
*/
- public byte[] messageDecrypt(byte[] cipher) throws Exception;
+ public byte[] messageDecrypt(byte[] cipher)
+ throws InvalidCipherTextException;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java
index 50243f73..4b172c8a 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java
@@ -2,6 +2,9 @@ package org.bouncycastle.pqc.crypto;
import org.bouncycastle.crypto.CipherParameters;
+/**
+ * Base interface for a PQC signing algorithm.
+ */
public interface MessageSigner
{
/**
@@ -23,7 +26,7 @@ public interface MessageSigner
public byte[] generateSignature(byte[] message);
/**
- * verify the message message against the signature values r and s.
+ * verify the message message against the signature value.
*
* @param message the message that was supposed to have been signed.
* @param signature the signature of the message
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java
index 198e5d29..7854bea0 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java
@@ -12,7 +12,6 @@ import org.bouncycastle.pqc.math.linearalgebra.GoppaCode;
import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
-import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2m;
/**
@@ -89,10 +88,6 @@ public class McElieceCCA2KeyPairGenerator
// irreducible Goppa polynomial
PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t,
PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random);
- PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp);
-
- // matrix for computing square roots in (GF(2^m))^t
- PolynomialGF2mSmallM[] qInv = ring.getSquareRootMatrix();
// generate canonical check matrix
GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp);
@@ -109,9 +104,8 @@ public class McElieceCCA2KeyPairGenerator
int k = shortG.getNumRows();
// generate keys
- McElieceCCA2PublicKeyParameters pubKey = new McElieceCCA2PublicKeyParameters(OID, n, t, shortG, mcElieceCCA2Params.getParameters());
- McElieceCCA2PrivateKeyParameters privKey = new McElieceCCA2PrivateKeyParameters(OID, n, k,
- field, gp, p, h, qInv, mcElieceCCA2Params.getParameters());
+ McElieceCCA2PublicKeyParameters pubKey = new McElieceCCA2PublicKeyParameters(n, t, shortG, mcElieceCCA2Params.getParameters().getDigest());
+ McElieceCCA2PrivateKeyParameters privKey = new McElieceCCA2PrivateKeyParameters(n, k, field, gp, p, mcElieceCCA2Params.getParameters().getDigest());
// return key pair
return new AsymmetricCipherKeyPair(pubKey, privKey);
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java
index 80114767..8e8ac0d5 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java
@@ -6,18 +6,18 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
public class McElieceCCA2KeyParameters
extends AsymmetricKeyParameter
{
- private McElieceCCA2Parameters params;
+ private String params;
public McElieceCCA2KeyParameters(
boolean isPrivate,
- McElieceCCA2Parameters params)
+ String params)
{
super(isPrivate);
this.params = params;
}
- public McElieceCCA2Parameters getParameters()
+ public String getDigest()
{
return params;
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java
index 7f800106..5ba2d2b2 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java
@@ -1,51 +1,113 @@
package org.bouncycastle.pqc.crypto.mceliece;
-
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-
-/**
- * This class provides a specification for the parameters of the CCA2-secure
- * variants of the McEliece PKCS that are used with
- * {@link McElieceFujisakiCipher}, {@link McElieceKobaraImaiCipher}, and
- * {@link McEliecePointchevalCipher}.
- *
- * @see McElieceFujisakiCipher
- * @see McElieceKobaraImaiCipher
- * @see McEliecePointchevalCipher
- */
public class McElieceCCA2Parameters
extends McElieceParameters
{
+ private final String digest;
+ /**
+ * Constructor. Set the default parameters: extension degree.
+ */
+ public McElieceCCA2Parameters()
+ {
+ this(DEFAULT_M, DEFAULT_T, "SHA-256");
+ }
- public Digest digest;
+ public McElieceCCA2Parameters(String digest)
+ {
+ this(DEFAULT_M, DEFAULT_T, digest);
+ }
+ /**
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
+ */
+ public McElieceCCA2Parameters(int keysize)
+ {
+ this(keysize, "SHA-256");
+ }
/**
- * Construct the default parameters.
- * The default message digest is SHA256.
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @param digest CCA2 mode digest
+ * @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
*/
- public McElieceCCA2Parameters()
+ public McElieceCCA2Parameters(int keysize, String digest)
{
- this.digest = new SHA256Digest();
+ super(keysize);
+ this.digest = digest;
}
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
+ */
public McElieceCCA2Parameters(int m, int t)
{
- super(m, t);
- this.digest = new SHA256Digest();
+ this(m, t, "SHA-256");
}
- public McElieceCCA2Parameters(Digest digest)
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
+ */
+ public McElieceCCA2Parameters(int m, int t, String digest)
{
+ super(m, t);
this.digest = digest;
}
- public Digest getDigest()
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
+ * <tt>poly</tt> is not an irreducible field polynomial.
+ */
+ public McElieceCCA2Parameters(int m, int t, int poly)
{
- return this.digest;
+ this(m, t, poly, "SHA-256");
}
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @param digest CCA2 mode digest
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
+ * <tt>poly</tt> is not an irreducible field polynomial.
+ */
+ public McElieceCCA2Parameters(int m, int t, int poly, String digest)
+ {
+ super(m, t, poly);
+ this.digest = digest;
+ }
+ /**
+ * Return the CCA2 mode digest if set.
+ *
+ * @return the CCA2 digest to use, null if not present.
+ */
+ public String getDigest()
+ {
+ return digest;
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java
index 726add15..d6dba73a 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java
@@ -11,7 +11,7 @@ import org.bouncycastle.pqc.math.linearalgebra.Vector;
/**
* Core operations for the CCA-secure variants of McEliece.
*/
-public final class McElieceCCA2Primitives
+final class McElieceCCA2Primitives
{
/**
@@ -35,7 +35,7 @@ public final class McElieceCCA2Primitives
GF2Vector m, GF2Vector z)
{
- GF2Matrix matrixG = pubKey.getMatrixG();
+ GF2Matrix matrixG = pubKey.getG();
Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
return (GF2Vector)mG.add(z);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java
index b8e1c24d..ed5bea87 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java
@@ -3,8 +3,10 @@ package org.bouncycastle.pqc.crypto.mceliece;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
+import org.bouncycastle.pqc.math.linearalgebra.GoppaCode;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2m;
/**
*
@@ -14,10 +16,6 @@ import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
public class McElieceCCA2PrivateKeyParameters
extends McElieceCCA2KeyParameters
{
-
- // the OID of the algorithm
- private String oid;
-
// the length of the code
private int n;
@@ -47,56 +45,24 @@ public class McElieceCCA2PrivateKeyParameters
* @param field the finite field <tt>GF(2<sup>m</sup>)</tt>
* @param gp the irreducible Goppa polynomial
* @param p the permutation
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2^m))^t</tt>
- * @param params McElieceCCA2Parameters
+ * @param digest McElieceCCA2Parameters
*/
- public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
- PolynomialGF2mSmallM[] qInv, McElieceCCA2Parameters params)
+ public McElieceCCA2PrivateKeyParameters(int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p, String digest)
{
- super(true, params);
- this.oid = oid;
+ super(true, digest);
this.n = n;
this.k = k;
this.field = field;
this.goppaPoly = gp;
this.p = p;
- this.h = h;
- this.qInv = qInv;
- }
- /**
- * Constructor.
- *
- * @param n the length of the code
- * @param k the dimension of the code
- * @param encFieldPoly the encoded field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param encGoppaPoly the encoded irreducible Goppa polynomial
- * @param encP the encoded permutation
- * @param encH the encoded canonical check matrix
- * @param encQInv the encoded matrix used to compute square roots in
- * <tt>(GF(2^m))^t</tt>
- * @param params McElieceCCA2Parameters
- */
- public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, byte[] encFieldPoly,
- byte[] encGoppaPoly, byte[] encP, byte[] encH, byte[][] encQInv, McElieceCCA2Parameters params)
- {
- super(true, params);
- this.oid = oid;
- this.n = n;
- this.k = k;
- field = new GF2mField(encFieldPoly);
- goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
- p = new Permutation(encP);
- h = new GF2Matrix(encH);
- qInv = new PolynomialGF2mSmallM[encQInv.length];
- for (int i = 0; i < encQInv.length; i++)
- {
- qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
- }
+ this.h = GoppaCode.createCanonicalCheckMatrix(field, gp);
+
+ PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp);
+
+ // matrix for computing square roots in (GF(2^m))^t
+ this.qInv = ring.getSquareRootMatrix();
}
/**
@@ -162,11 +128,4 @@ public class McElieceCCA2PrivateKeyParameters
{
return qInv;
}
-
- public String getOIDString()
- {
- return oid;
-
- }
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java
index 4d14f8b7..59105262 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java
@@ -10,10 +10,6 @@ import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
public class McElieceCCA2PublicKeyParameters
extends McElieceCCA2KeyParameters
{
-
- // the OID of the algorithm
- private String oid;
-
// the length of the code
private int n;
@@ -25,36 +21,18 @@ public class McElieceCCA2PublicKeyParameters
/**
* Constructor.
- *
- * @param n length of the code
+ * @param n length of the code
* @param t error correction capability
* @param matrix generator matrix
- * @param params McElieceCCA2Parameters
+ * @param digest McElieceCCA2Parameters
*/
- public McElieceCCA2PublicKeyParameters(String oid, int n, int t, GF2Matrix matrix, McElieceCCA2Parameters params)
+ public McElieceCCA2PublicKeyParameters(int n, int t, GF2Matrix matrix, String digest)
{
- super(false, params);
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.matrixG = new GF2Matrix(matrix);
- }
+ super(false, digest);
- /**
- * Constructor.
- *
- * @param n length of the code
- * @param t error correction capability of the code
- * @param encMatrix encoded generator matrix
- * @param params McElieceCCA2Parameters
- */
- public McElieceCCA2PublicKeyParameters(String oid, int n, int t, byte[] encMatrix, McElieceCCA2Parameters params)
- {
- super(false, params);
- this.oid = oid;
this.n = n;
this.t = t;
- this.matrixG = new GF2Matrix(encMatrix);
+ this.matrixG = new GF2Matrix(matrix);
}
/**
@@ -76,7 +54,7 @@ public class McElieceCCA2PublicKeyParameters
/**
* @return the generator matrix
*/
- public GF2Matrix getMatrixG()
+ public GF2Matrix getG()
{
return matrixG;
}
@@ -88,10 +66,4 @@ public class McElieceCCA2PublicKeyParameters
{
return matrixG.getNumRows();
}
-
- public String getOIDString()
- {
- return oid;
-
- }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCipher.java
index b4eecfb3..4c87e005 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCipher.java
@@ -3,6 +3,7 @@ package org.bouncycastle.pqc.crypto.mceliece;
import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.pqc.crypto.MessageEncryptor;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
@@ -21,7 +22,7 @@ import org.bouncycastle.pqc.math.linearalgebra.Vector;
* codes. The trapdoor for the McEliece cryptosystem using Goppa codes is the
* knowledge of the Goppa polynomial used to generate the code.
*/
-public class McEliecePKCSCipher
+public class McElieceCipher
implements MessageEncryptor
{
@@ -43,14 +44,15 @@ public class McEliecePKCSCipher
// The maximum number of bytes the cipher can encrypt
public int cipherTextSize;
- McElieceKeyParameters key;
+ private McElieceKeyParameters key;
+ private boolean forEncryption;
- public void init(boolean forSigning,
+ public void init(boolean forEncryption,
CipherParameters param)
{
-
- if (forSigning)
+ this.forEncryption = forEncryption;
+ if (forEncryption)
{
if (param instanceof ParametersWithRandom)
{
@@ -76,7 +78,6 @@ public class McEliecePKCSCipher
}
-
/**
* Return the key size of the given key object.
*
@@ -129,6 +130,10 @@ public class McEliecePKCSCipher
*/
public byte[] messageEncrypt(byte[] input)
{
+ if (!forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
GF2Vector m = computeMessageRepresentative(input);
GF2Vector z = new GF2Vector(n, t, sr);
@@ -155,8 +160,13 @@ public class McEliecePKCSCipher
* @throws Exception if the cipher text is invalid.
*/
public byte[] messageDecrypt(byte[] input)
- throws Exception
+ throws InvalidCipherTextException
{
+ if (forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
+
GF2Vector vec = GF2Vector.OS2VP(n, input);
McEliecePrivateKeyParameters privKey = (McEliecePrivateKeyParameters)key;
GF2mField field = privKey.getField();
@@ -198,7 +208,7 @@ public class McEliecePKCSCipher
}
private byte[] computeMessage(GF2Vector mr)
- throws Exception
+ throws InvalidCipherTextException
{
byte[] mrBytes = mr.getEncoded();
// find first non-zero byte
@@ -211,7 +221,7 @@ public class McEliecePKCSCipher
// check if padding byte is valid
if (index<0 || mrBytes[index] != 0x01)
{
- throw new Exception("Bad Padding: invalid ciphertext");
+ throw new InvalidCipherTextException("Bad Padding: invalid ciphertext");
}
// extract and return message
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java
index c414540f..52e5753f 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java
@@ -4,6 +4,7 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.prng.DigestRandomGenerator;
@@ -23,8 +24,6 @@ import org.bouncycastle.pqc.math.linearalgebra.GF2Vector;
public class McElieceFujisakiCipher
implements MessageEncryptor
{
-
-
/**
* The OID of the algorithm.
*/
@@ -42,13 +41,14 @@ public class McElieceFujisakiCipher
private int n, k, t;
McElieceCCA2KeyParameters key;
+ private boolean forEncryption;
- public void init(boolean forSigning,
+ public void init(boolean forEncryption,
CipherParameters param)
{
-
- if (forSigning)
+ this.forEncryption = forEncryption;
+ if (forEncryption)
{
if (param instanceof ParametersWithRandom)
{
@@ -71,7 +71,6 @@ public class McElieceFujisakiCipher
this.key = (McElieceCCA2PrivateKeyParameters)param;
this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key);
}
-
}
@@ -82,7 +81,6 @@ public class McElieceFujisakiCipher
if (key instanceof McElieceCCA2PublicKeyParameters)
{
return ((McElieceCCA2PublicKeyParameters)key).getN();
-
}
if (key instanceof McElieceCCA2PrivateKeyParameters)
{
@@ -96,7 +94,7 @@ public class McElieceFujisakiCipher
private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
{
this.sr = sr != null ? sr : new SecureRandom();
- this.messDigest = pubKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(pubKey.getDigest());
n = pubKey.getN();
k = pubKey.getK();
t = pubKey.getT();
@@ -105,15 +103,18 @@ public class McElieceFujisakiCipher
public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
{
- this.messDigest = privKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(privKey.getDigest());
n = privKey.getN();
t = privKey.getT();
}
public byte[] messageEncrypt(byte[] input)
- throws Exception
{
+ if (!forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
// generate random vector r of length k bits
GF2Vector r = new GF2Vector(k, sr);
@@ -157,8 +158,12 @@ public class McElieceFujisakiCipher
}
public byte[] messageDecrypt(byte[] input)
- throws Exception
+ throws InvalidCipherTextException
{
+ if (forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
int c1Len = (n + 7) >> 3;
int c2Len = input.length - c1Len;
@@ -170,8 +175,7 @@ public class McElieceFujisakiCipher
// decrypt c1 ...
GF2Vector hrmVec = GF2Vector.OS2VP(n, c1);
- GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key,
- hrmVec);
+ GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, hrmVec);
byte[] rBytes = decC1[0].getEncoded();
// ... and obtain error vector z
GF2Vector z = decC1[1];
@@ -205,14 +209,10 @@ public class McElieceFujisakiCipher
// check that Conv(H(m||r)) = z
if (!hrmVec.equals(z))
{
-
- throw new Exception("Bad Padding: invalid ciphertext");
-
+ throw new InvalidCipherTextException("Bad Padding: invalid ciphertext");
}
// return plaintext m
return mBytes;
}
-
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java
deleted file mode 100644
index 423e6ff8..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.bouncycastle.pqc.crypto.mceliece;
-
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.pqc.crypto.MessageEncryptor;
-
-// TODO should implement some interface?
-public class McElieceFujisakiDigestCipher
-{
-
- private final Digest messDigest;
-
- private final MessageEncryptor mcElieceCCA2Cipher;
-
- private boolean forEncrypting;
-
-
- public McElieceFujisakiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
- {
- this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
- this.messDigest = messDigest;
- }
-
-
- public void init(boolean forEncrypting,
- CipherParameters param)
- {
-
- this.forEncrypting = forEncrypting;
- AsymmetricKeyParameter k;
-
- if (param instanceof ParametersWithRandom)
- {
- k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
- }
- else
- {
- k = (AsymmetricKeyParameter)param;
- }
-
- if (forEncrypting && k.isPrivate())
- {
- throw new IllegalArgumentException("Encrypting Requires Public Key.");
- }
-
- if (!forEncrypting && !k.isPrivate())
- {
- throw new IllegalArgumentException("Decrypting Requires Private Key.");
- }
-
- reset();
-
- mcElieceCCA2Cipher.init(forEncrypting, param);
- }
-
-
- public byte[] messageEncrypt()
- {
- if (!forEncrypting)
- {
- throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for encrypting.");
- }
-
- byte[] hash = new byte[messDigest.getDigestSize()];
- messDigest.doFinal(hash, 0);
- byte[] enc = null;
-
- try
- {
- enc = mcElieceCCA2Cipher.messageEncrypt(hash);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return enc;
- }
-
-
- public byte[] messageDecrypt(byte[] ciphertext)
- {
- byte[] output = null;
- if (forEncrypting)
- {
- throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for decrypting.");
- }
-
-
- try
- {
- output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return output;
- }
-
-
- public void update(byte b)
- {
- messDigest.update(b);
-
- }
-
- public void update(byte[] in, int off, int len)
- {
- messDigest.update(in, off, len);
-
- }
-
-
- public void reset()
- {
- messDigest.reset();
-
- }
-
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
index 6ad7fc2f..b511feec 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
@@ -129,9 +129,8 @@ public class McElieceKeyPairGenerator
// generate keys
- McEliecePublicKeyParameters pubKey = new McEliecePublicKeyParameters(OID, n, t, g, mcElieceParams.getParameters());
- McEliecePrivateKeyParameters privKey = new McEliecePrivateKeyParameters(OID, n, k,
- field, gp, matrixSandInverse[1], p1, p2, h, sqRootMatrix, mcElieceParams.getParameters());
+ McEliecePublicKeyParameters pubKey = new McEliecePublicKeyParameters(n, t, g);
+ McEliecePrivateKeyParameters privKey = new McEliecePrivateKeyParameters(n, k, field, gp, p1, p2, matrixSandInverse[1]);
// return key pair
return new AsymmetricCipherKeyPair(pubKey, privKey);
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java
index fe3ebf94..89e32325 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java
@@ -4,6 +4,7 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.prng.DigestRandomGenerator;
@@ -46,13 +47,14 @@ public class McElieceKobaraImaiCipher
* The McEliece main parameters
*/
private int n, k, t;
+ private boolean forEncryption;
- public void init(boolean forSigning,
+ public void init(boolean forEncryption,
CipherParameters param)
{
-
- if (forSigning)
+ this.forEncryption = forEncryption;
+ if (forEncryption)
{
if (param instanceof ParametersWithRandom)
{
@@ -100,7 +102,7 @@ public class McElieceKobaraImaiCipher
private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
{
- this.messDigest = pubKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(pubKey.getDigest());
n = pubKey.getN();
k = pubKey.getK();
t = pubKey.getT();
@@ -109,15 +111,18 @@ public class McElieceKobaraImaiCipher
public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
{
- this.messDigest = privKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(privKey.getDigest());
n = privKey.getN();
k = privKey.getK();
t = privKey.getT();
}
public byte[] messageEncrypt(byte[] input)
- throws Exception
{
+ if (!forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
int c2Len = messDigest.getDigestSize();
int c4Len = k >> 3;
@@ -212,14 +217,18 @@ public class McElieceKobaraImaiCipher
public byte[] messageDecrypt(byte[] input)
- throws Exception
+ throws InvalidCipherTextException
{
+ if (forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
int nDiv8 = n >> 3;
if (input.length < nDiv8)
{
- throw new Exception("Bad Padding: Ciphertext too short.");
+ throw new InvalidCipherTextException("Bad Padding: Ciphertext too short.");
}
int c2Len = messDigest.getDigestSize();
@@ -299,7 +308,7 @@ public class McElieceKobaraImaiCipher
if (mConstPrime.length < c1Len)
{
- throw new Exception("Bad Padding: invalid ciphertext");
+ throw new InvalidCipherTextException("Bad Padding: invalid ciphertext");
}
byte[][] temp = ByteUtils.split(mConstPrime, c1Len
@@ -309,11 +318,9 @@ public class McElieceKobaraImaiCipher
if (!ByteUtils.equals(constPrime, PUBLIC_CONSTANT))
{
- throw new Exception("Bad Padding: invalid ciphertext");
+ throw new InvalidCipherTextException("Bad Padding: invalid ciphertext");
}
return mr;
}
-
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java
deleted file mode 100644
index 365f387c..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.bouncycastle.pqc.crypto.mceliece;
-
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.pqc.crypto.MessageEncryptor;
-
-// TODO should implement some interface?
-public class McElieceKobaraImaiDigestCipher
-{
-
- private final Digest messDigest;
-
- private final MessageEncryptor mcElieceCCA2Cipher;
-
- private boolean forEncrypting;
-
-
- public McElieceKobaraImaiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
- {
- this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
- this.messDigest = messDigest;
- }
-
-
- public void init(boolean forEncrypting,
- CipherParameters param)
- {
-
- this.forEncrypting = forEncrypting;
- AsymmetricKeyParameter k;
-
- if (param instanceof ParametersWithRandom)
- {
- k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
- }
- else
- {
- k = (AsymmetricKeyParameter)param;
- }
-
- if (forEncrypting && k.isPrivate())
- {
- throw new IllegalArgumentException("Encrypting Requires Public Key.");
- }
-
- if (!forEncrypting && !k.isPrivate())
- {
- throw new IllegalArgumentException("Decrypting Requires Private Key.");
- }
-
- reset();
-
- mcElieceCCA2Cipher.init(forEncrypting, param);
- }
-
-
- public byte[] messageEncrypt()
- {
- if (!forEncrypting)
- {
- throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for encrypting.");
- }
-
- byte[] hash = new byte[messDigest.getDigestSize()];
- messDigest.doFinal(hash, 0);
- byte[] enc = null;
-
- try
- {
- enc = mcElieceCCA2Cipher.messageEncrypt(hash);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return enc;
- }
-
-
- public byte[] messageDecrypt(byte[] ciphertext)
- {
- byte[] output = null;
- if (forEncrypting)
- {
- throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for decrypting.");
- }
-
-
- try
- {
- output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return output;
- }
-
-
- public void update(byte b)
- {
- messDigest.update(b);
-
- }
-
- public void update(byte[] in, int off, int len)
- {
- messDigest.update(in, off, len);
-
- }
-
-
- public void reset()
- {
- messDigest.reset();
-
- }
-
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java
deleted file mode 100644
index d8e6ba25..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.bouncycastle.pqc.crypto.mceliece;
-
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.pqc.crypto.MessageEncryptor;
-
-// TODO should implement some interface?
-public class McEliecePKCSDigestCipher
-{
-
- private final Digest messDigest;
-
- private final MessageEncryptor mcElieceCipher;
-
- private boolean forEncrypting;
-
-
- public McEliecePKCSDigestCipher(MessageEncryptor mcElieceCipher, Digest messDigest)
- {
- this.mcElieceCipher = mcElieceCipher;
- this.messDigest = messDigest;
- }
-
-
- public void init(boolean forEncrypting,
- CipherParameters param)
- {
-
- this.forEncrypting = forEncrypting;
- AsymmetricKeyParameter k;
-
- if (param instanceof ParametersWithRandom)
- {
- k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
- }
- else
- {
- k = (AsymmetricKeyParameter)param;
- }
-
- if (forEncrypting && k.isPrivate())
- {
- throw new IllegalArgumentException("Encrypting Requires Public Key.");
- }
-
- if (!forEncrypting && !k.isPrivate())
- {
- throw new IllegalArgumentException("Decrypting Requires Private Key.");
- }
-
- reset();
-
- mcElieceCipher.init(forEncrypting, param);
- }
-
-
- public byte[] messageEncrypt()
- {
- if (!forEncrypting)
- {
- throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for encrypting.");
- }
-
- byte[] hash = new byte[messDigest.getDigestSize()];
- messDigest.doFinal(hash, 0);
- byte[] enc = null;
-
- try
- {
- enc = mcElieceCipher.messageEncrypt(hash);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return enc;
- }
-
-
- public byte[] messageDecrypt(byte[] ciphertext)
- {
- byte[] output = null;
- if (forEncrypting)
- {
- throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for decrypting.");
- }
-
-
- try
- {
- output = mcElieceCipher.messageDecrypt(ciphertext);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return output;
- }
-
-
- public void update(byte b)
- {
- messDigest.update(b);
-
- }
-
- public void update(byte[] in, int off, int len)
- {
- messDigest.update(in, off, len);
-
- }
-
-
- public void reset()
- {
- messDigest.reset();
-
- }
-
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java
index e90c7846..62beb331 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java
@@ -1,6 +1,7 @@
package org.bouncycastle.pqc.crypto.mceliece;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2;
public class McElieceParameters
@@ -37,6 +38,8 @@ public class McElieceParameters
*/
private int fieldPoly;
+ private Digest digest;
+
/**
* Constructor. Set the default parameters: extension degree.
*/
@@ -45,6 +48,11 @@ public class McElieceParameters
this(DEFAULT_M, DEFAULT_T);
}
+ public McElieceParameters(Digest digest)
+ {
+ this(DEFAULT_M, DEFAULT_T, digest);
+ }
+
/**
* Constructor.
*
@@ -52,7 +60,18 @@ public class McElieceParameters
* @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
*/
public McElieceParameters(int keysize)
- throws IllegalArgumentException
+ {
+ this(keysize, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @param digest CCA2 mode digest
+ * @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
+ */
+ public McElieceParameters(int keysize, Digest digest)
{
if (keysize < 1)
{
@@ -68,6 +87,7 @@ public class McElieceParameters
t = n >>> 1;
t /= m;
fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ this.digest = digest;
}
/**
@@ -79,7 +99,19 @@ public class McElieceParameters
* <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
*/
public McElieceParameters(int m, int t)
- throws IllegalArgumentException
+ {
+ this(m, t, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
+ */
+ public McElieceParameters(int m, int t, Digest digest)
{
if (m < 1)
{
@@ -101,6 +133,7 @@ public class McElieceParameters
}
this.t = t;
fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ this.digest = digest;
}
/**
@@ -114,7 +147,22 @@ public class McElieceParameters
* <tt>poly</tt> is not an irreducible field polynomial.
*/
public McElieceParameters(int m, int t, int poly)
- throws IllegalArgumentException
+ {
+ this(m, t, poly, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @param digest CCA2 mode digest
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
+ * <tt>poly</tt> is not an irreducible field polynomial.
+ */
+ public McElieceParameters(int m, int t, int poly, Digest digest)
{
this.m = m;
if (m < 1)
@@ -145,6 +193,7 @@ public class McElieceParameters
throw new IllegalArgumentException(
"polynomial is not a field polynomial for GF(2^m)");
}
+ this.digest = digest;
}
/**
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java
index 854d79e0..c24b5b41 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java
@@ -4,6 +4,7 @@ import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.prng.DigestRandomGenerator;
@@ -38,12 +39,14 @@ public class McEliecePointchevalCipher
private int n, k, t;
McElieceCCA2KeyParameters key;
+ private boolean forEncryption;
- public void init(boolean forSigning,
+ public void init(boolean forEncryption,
CipherParameters param)
{
+ this.forEncryption = forEncryption;
- if (forSigning)
+ if (forEncryption)
{
if (param instanceof ParametersWithRandom)
{
@@ -108,7 +111,7 @@ public class McEliecePointchevalCipher
public void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey)
{
this.sr = sr != null ? sr : new SecureRandom();
- this.messDigest = pubKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(pubKey.getDigest());
n = pubKey.getN();
k = pubKey.getK();
t = pubKey.getT();
@@ -116,15 +119,18 @@ public class McEliecePointchevalCipher
public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey)
{
- this.messDigest = privKey.getParameters().getDigest();
+ this.messDigest = Utils.getDigest(privKey.getDigest());
n = privKey.getN();
k = privKey.getK();
t = privKey.getT();
}
public byte[] messageEncrypt(byte[] input)
- throws Exception
{
+ if (!forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
int kDiv8 = k >> 3;
@@ -180,8 +186,12 @@ public class McEliecePointchevalCipher
}
public byte[] messageDecrypt(byte[] input)
- throws Exception
+ throws InvalidCipherTextException
{
+ if (forEncryption)
+ {
+ throw new IllegalStateException("cipher initialised for decryption");
+ }
int c1Len = (n + 7) >> 3;
int c2Len = input.length - c1Len;
@@ -226,7 +236,7 @@ public class McEliecePointchevalCipher
// check that Conv(H(m||r)) = z
if (!c1Vec.equals(z))
{
- throw new Exception("Bad Padding: Invalid ciphertext.");
+ throw new InvalidCipherTextException("Bad Padding: Invalid ciphertext.");
}
// split (m||r) to obtain m
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java
deleted file mode 100644
index 8a1ed62a..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.bouncycastle.pqc.crypto.mceliece;
-
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.pqc.crypto.MessageEncryptor;
-
-// TODO should implement some interface?
-public class McEliecePointchevalDigestCipher
-{
-
- private final Digest messDigest;
-
- private final MessageEncryptor mcElieceCCA2Cipher;
-
- private boolean forEncrypting;
-
-
- public McEliecePointchevalDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest)
- {
- this.mcElieceCCA2Cipher = mcElieceCCA2Cipher;
- this.messDigest = messDigest;
- }
-
-
- public void init(boolean forEncrypting,
- CipherParameters param)
- {
-
- this.forEncrypting = forEncrypting;
- AsymmetricKeyParameter k;
-
- if (param instanceof ParametersWithRandom)
- {
- k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters();
- }
- else
- {
- k = (AsymmetricKeyParameter)param;
- }
-
- if (forEncrypting && k.isPrivate())
- {
- throw new IllegalArgumentException("Encrypting Requires Public Key.");
- }
-
- if (!forEncrypting && !k.isPrivate())
- {
- throw new IllegalArgumentException("Decrypting Requires Private Key.");
- }
-
- reset();
-
- mcElieceCCA2Cipher.init(forEncrypting, param);
- }
-
-
- public byte[] messageEncrypt()
- {
- if (!forEncrypting)
- {
- throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for encrypting.");
- }
-
- byte[] hash = new byte[messDigest.getDigestSize()];
- messDigest.doFinal(hash, 0);
- byte[] enc = null;
-
- try
- {
- enc = mcElieceCCA2Cipher.messageEncrypt(hash);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return enc;
- }
-
-
- public byte[] messageDecrypt(byte[] ciphertext)
- {
- byte[] output = null;
- if (forEncrypting)
- {
- throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for decrypting.");
- }
-
-
- try
- {
- output = mcElieceCCA2Cipher.messageDecrypt(ciphertext);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- return output;
- }
-
-
- public void update(byte b)
- {
- messDigest.update(b);
-
- }
-
- public void update(byte[] in, int off, int len)
- {
- messDigest.update(in, off, len);
-
- }
-
-
- public void reset()
- {
- messDigest.reset();
-
- }
-
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java
index d40256aa..a21de4ec 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java
@@ -2,8 +2,10 @@ package org.bouncycastle.pqc.crypto.mceliece;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
+import org.bouncycastle.pqc.math.linearalgebra.GoppaCode;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2m;
public class McEliecePrivateKeyParameters
@@ -43,43 +45,39 @@ public class McEliecePrivateKeyParameters
/**
* Constructor.
*
- * @param oid
* @param n the length of the code
* @param k the dimension of the code
* @param field the field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param goppaPoly the irreducible Goppa polynomial
- * @param sInv the matrix <tt>S<sup>-1</sup></tt>
+* <tt>GF(2<sup>m</sup>)</tt>
+ * @param gp the irreducible Goppa polynomial
* @param p1 the permutation used to generate the systematic check
- * matrix
+* matrix
* @param p2 the permutation used to compute the public generator
- * matrix
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- * @param params McElieceParameters
+* matrix
+ * @param sInv the matrix <tt>S<sup>-1</sup></tt>
*/
- public McEliecePrivateKeyParameters(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
- Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv, McElieceParameters params)
+ public McEliecePrivateKeyParameters(int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p1, Permutation p2, GF2Matrix sInv)
{
- super(true, params);
- this.oid = oid;
+ super(true, null);
this.k = k;
this.n = n;
this.field = field;
- this.goppaPoly = goppaPoly;
+ this.goppaPoly = gp;
this.sInv = sInv;
this.p1 = p1;
this.p2 = p2;
- this.h = h;
- this.qInv = qInv;
+ this.h = GoppaCode.createCanonicalCheckMatrix(field, gp);
+
+ PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp);
+
+ // matrix used to compute square roots in (GF(2^m))^t
+ this.qInv = ring.getSquareRootMatrix();
}
/**
* Constructor.
*
- * @param oid
* @param n the length of the code
* @param k the dimension of the code
* @param encField the encoded field polynomial defining the finite field
@@ -93,14 +91,12 @@ public class McEliecePrivateKeyParameters
* @param encH the encoded canonical check matrix
* @param encQInv the encoded matrix used to compute square roots in
* <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- * @param params McElieceParameters
*/
- public McEliecePrivateKeyParameters(String oid, int n, int k, byte[] encField,
+ public McEliecePrivateKeyParameters(int n, int k, byte[] encField,
byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2,
- byte[] encH, byte[][] encQInv, McElieceParameters params)
+ byte[] encH, byte[][] encQInv)
{
- super(true, params);
- this.oid = oid;
+ super(true, null);
this.n = n;
this.k = k;
field = new GF2mField(encField);
@@ -189,9 +185,5 @@ public class McEliecePrivateKeyParameters
return qInv;
}
- public String getOIDString()
- {
- return oid;
- }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java
index d94e00f8..507a8ced 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java
@@ -6,10 +6,6 @@ import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
public class McEliecePublicKeyParameters
extends McElieceKeyParameters
{
-
- // the OID of the algorithm
- private String oid;
-
// the length of the code
private int n;
@@ -22,40 +18,19 @@ public class McEliecePublicKeyParameters
/**
* Constructor.
*
- * @param oid string representation of the OID for this key.
* @param n the length of the code
* @param t the error correction capability of the code
* @param g the generator matrix
- * @param params McElieceParameters
*/
- public McEliecePublicKeyParameters(String oid, int n, int t, GF2Matrix g, McElieceParameters params)
+ public McEliecePublicKeyParameters(int n, int t, GF2Matrix g)
{
- super(false, params);
- this.oid = oid;
+ super(false, null);
this.n = n;
this.t = t;
this.g = new GF2Matrix(g);
}
/**
- * Constructor.
- *
- * @param oid
- * @param n the length of the code
- * @param t the error correction capability of the code
- * @param encG the encoded generator matrix
- * @param params McElieceParameters
- */
- public McEliecePublicKeyParameters(String oid, int t, int n, byte[] encG, McElieceParameters params)
- {
- super(false, params);
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.g = new GF2Matrix(encG);
- }
-
- /**
* @return the length of the code
*/
public int getN()
@@ -79,12 +54,6 @@ public class McEliecePublicKeyParameters
return g;
}
- public String getOIDString()
- {
- return oid;
-
- }
-
/**
* @return the dimension of the code
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Utils.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Utils.java
new file mode 100644
index 00000000..b3fba147
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Utils.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.pqc.crypto.mceliece;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+
+class Utils
+{
+ static Digest getDigest(String digestName)
+ {
+ if (digestName.equals("SHA-1"))
+ {
+ return new SHA1Digest();
+ }
+ if (digestName.equals("SHA-224"))
+ {
+ return new SHA224Digest();
+ }
+ if (digestName.equals("SHA-256"))
+ {
+ return new SHA256Digest();
+ }
+ if (digestName.equals("SHA-384"))
+ {
+ return new SHA384Digest();
+ }
+ if (digestName.equals("SHA-512"))
+ {
+ return new SHA512Digest();
+ }
+
+ throw new IllegalArgumentException("unrecognised digest algorithm: " + digestName);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ChaCha20.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ChaCha20.java
new file mode 100644
index 00000000..e21ea4d0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ChaCha20.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.crypto.engines.ChaChaEngine;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+class ChaCha20
+{
+ static void process(byte[] key, byte[] nonce, byte[] buf, int off, int len)
+ {
+ ChaChaEngine e = new ChaChaEngine(20);
+ e.init(true, new ParametersWithIV(new KeyParameter(key), nonce));
+ e.processBytes(buf, off, len, buf, off);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ErrorCorrection.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ErrorCorrection.java
new file mode 100644
index 00000000..e2af3208
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/ErrorCorrection.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.util.Arrays;
+
+class ErrorCorrection
+{
+ static int abs(int v)
+ {
+ int mask = v >> 31;
+ return (v ^ mask) - mask;
+ }
+
+ static int f(int[] v, int off0, int off1, int x)
+ {
+ int xit, t, r, b;
+
+ // Next 6 lines compute t = x/Params.Q;
+ b = x * 2730;
+ t = b >> 25;
+ b = x - t * Params.Q;
+ b = 12288 - b;
+ b >>= 31;
+ t -= b;
+
+ r = t & 1;
+ xit = t >> 1;
+ v[off0] = xit + r; // v0 = round(x/(2*Params.Q))
+
+ t -= 1;
+ r = t & 1;
+ v[off1] = (t >> 1) + r;
+
+ return abs(x-((v[off0]) * 2 * Params.Q));
+ }
+
+ static int g(int x)
+ {
+ int t, c, b;
+
+ // Next 6 lines compute t = x/(4 * Params.Q);
+ b = x * 2730;
+ t = b >> 27;
+ b = x - t * 49156;
+ b = 49155 - b;
+ b >>= 31;
+ t -= b;
+
+ c = t & 1;
+ t = (t >> 1) + c; // t = round(x/(8 * Params.Q))
+
+ t *= 8 * Params.Q;
+
+ return abs(t - x);
+ }
+
+ static void helpRec(short[] c, short[] v, byte[] seed, byte nonce)
+ {
+ byte[] iv = new byte[8];
+// iv[7] = nonce;
+ iv[0] = nonce;
+
+ byte[] rand = new byte[32];
+ ChaCha20.process(seed, iv, rand, 0, rand.length);
+
+// int32_t v0[4], v1[4], v_tmp[4], k;
+ int[] vs = new int[8], vTmp = new int[4];
+ int k;
+
+ for (int i = 0; i < 256; ++i)
+ {
+ int rBit = (rand[i >>> 3] >>> (i & 7)) & 1;
+
+ k = f(vs, 0, 4, 8 * v[ 0 + i] + 4 * rBit);
+ k += f(vs, 1, 5, 8 * v[256 + i] + 4 * rBit);
+ k += f(vs, 2, 6, 8 * v[512 + i] + 4 * rBit);
+ k += f(vs, 3, 7, 8 * v[768 + i] + 4 * rBit);
+
+ k = (2 * Params.Q - 1 - k) >> 31;
+
+ vTmp[0] = ((~k) & vs[0]) ^ (k & vs[4]);
+ vTmp[1] = ((~k) & vs[1]) ^ (k & vs[5]);
+ vTmp[2] = ((~k) & vs[2]) ^ (k & vs[6]);
+ vTmp[3] = ((~k) & vs[3]) ^ (k & vs[7]);
+
+ c[ 0 + i] = (short)((vTmp[0] - vTmp[3]) & 3);
+ c[256 + i] = (short)((vTmp[1] - vTmp[3]) & 3);
+ c[512 + i] = (short)((vTmp[2] - vTmp[3]) & 3);
+ c[768 + i] = (short)(( -k + 2 * vTmp[3]) & 3);
+ }
+ }
+
+ static short LDDecode(int xi0, int xi1, int xi2, int xi3)
+ {
+ int t;
+
+ t = g(xi0);
+ t += g(xi1);
+ t += g(xi2);
+ t += g(xi3);
+
+ t -= 8 * Params.Q;
+
+ return (short)(t >>> 31);
+ }
+
+ static void rec(byte[] key, short[] v, short[] c)
+ {
+ Arrays.fill(key, (byte)0);
+
+ int[] tmp = new int[4];
+ for(int i = 0; i < 256; ++i)
+ {
+ tmp[0] = 16 * Params.Q + 8 * (int)v[ 0 + i] - Params.Q * (2 * c[ 0 + i] + c[768 + i]);
+ tmp[1] = 16 * Params.Q + 8 * (int)v[256 + i] - Params.Q * (2 * c[256 + i] + c[768 + i]);
+ tmp[2] = 16 * Params.Q + 8 * (int)v[512 + i] - Params.Q * (2 * c[512 + i] + c[768 + i]);
+ tmp[3] = 16 * Params.Q + 8 * (int)v[768 + i] - Params.Q * ( c[768 + i]);
+
+ key[i >>> 3] |= LDDecode(tmp[0], tmp[1], tmp[2], tmp[3]) << (i & 7);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHAgreement.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHAgreement.java
new file mode 100644
index 00000000..47b20423
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHAgreement.java
@@ -0,0 +1,24 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class NHAgreement
+{
+ private NHPrivateKeyParameters privKey;
+
+ public void init(CipherParameters param)
+ {
+ privKey = (NHPrivateKeyParameters)param;
+ }
+
+ public byte[] calculateAgreement(CipherParameters otherPublicKey)
+ {
+ NHPublicKeyParameters pubKey = (NHPublicKeyParameters)otherPublicKey;
+
+ byte[] sharedValue = new byte[NewHope.AGREEMENT_SIZE];
+
+ NewHope.sharedA(sharedValue, privKey.secData, pubKey.pubData);
+
+ return sharedValue;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHExchangePairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHExchangePairGenerator.java
new file mode 100644
index 00000000..7c9f38d4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHExchangePairGenerator.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.pqc.crypto.ExchangePair;
+import org.bouncycastle.pqc.crypto.ExchangePairGenerator;
+
+public class NHExchangePairGenerator
+ implements ExchangePairGenerator
+{
+ private final SecureRandom random;
+
+ public NHExchangePairGenerator(SecureRandom random)
+ {
+ this.random = random;
+ }
+
+ public ExchangePair GenerateExchange(AsymmetricKeyParameter senderPublicKey)
+ {
+ NHPublicKeyParameters pubKey = (NHPublicKeyParameters)senderPublicKey;
+
+ byte[] sharedValue = new byte[NewHope.AGREEMENT_SIZE];
+ byte[] publicKeyValue = new byte[NewHope.SENDB_BYTES];
+
+ NewHope.sharedB(random, sharedValue, publicKeyValue, pubKey.pubData);
+
+ return new ExchangePair(new NHPublicKeyParameters(publicKeyValue), sharedValue);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHKeyPairGenerator.java
new file mode 100644
index 00000000..e5115d7a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHKeyPairGenerator.java
@@ -0,0 +1,28 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class NHKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private SecureRandom random;
+
+ public void init(KeyGenerationParameters param)
+ {
+ this.random = param.getRandom();
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ byte[] pubData = new byte[NewHope.SENDA_BYTES];
+ short[] secData = new short[NewHope.POLY_SIZE];
+
+ NewHope.keygen(random, pubData, secData);
+
+ return new AsymmetricCipherKeyPair(new NHPublicKeyParameters(pubData), new NHPrivateKeyParameters(secData));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPrivateKeyParameters.java
new file mode 100644
index 00000000..49b0f5fb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPrivateKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class NHPrivateKeyParameters
+ extends AsymmetricKeyParameter
+{
+ final short[] secData;
+
+ public NHPrivateKeyParameters(short[] secData)
+ {
+ super(true);
+
+ this.secData = Arrays.clone(secData);
+ }
+
+ public short[] getSecData()
+ {
+ return Arrays.clone(secData);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPublicKeyParameters.java
new file mode 100644
index 00000000..c0c59345
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NHPublicKeyParameters.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class NHPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ final byte[] pubData;
+
+ public NHPublicKeyParameters(byte[] pubData)
+ {
+ super(false);
+ this.pubData = Arrays.clone(pubData);
+ }
+
+ /**
+ * Return the public key data.
+ *
+ * @return the public key values.
+ */
+ public byte[] getPubData()
+ {
+ return Arrays.clone(pubData);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NTT.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NTT.java
new file mode 100644
index 00000000..9f140295
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NTT.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+class NTT
+{
+ private static final short[] BitReverseTable = { 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704,
+ 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864, 224, 736, 480, 992, 16, 528, 272, 784, 144,
+ 656, 400, 912, 80, 592, 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944, 112, 624, 368, 880,
+ 240, 752, 496, 1008, 8, 520, 264, 776, 136, 648, 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296,
+ 808, 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, 24, 536, 280, 792, 152, 664, 408, 920, 88,
+ 600, 344, 856, 216, 728, 472, 984, 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760, 504,
+ 1016, 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836, 196, 708, 452, 964, 36, 548, 292, 804, 164, 676,
+ 420, 932, 100, 612, 356, 868, 228, 740, 484, 996, 20, 532, 276, 788, 148, 660, 404, 916, 84, 596, 340, 852, 212,
+ 724, 468, 980, 52, 564, 308, 820, 180, 692, 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, 12, 524, 268,
+ 780, 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556, 300, 812, 172, 684, 428, 940, 108, 620,
+ 364, 876, 236, 748, 492, 1004, 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732, 476, 988, 60,
+ 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892, 252, 764, 508, 1020, 2, 514, 258, 770, 130, 642, 386,
+ 898, 66, 578, 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930, 98, 610, 354, 866, 226, 738,
+ 482, 994, 18, 530, 274, 786, 146, 658, 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818, 178,
+ 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, 10, 522, 266, 778, 138, 650, 394, 906, 74, 586, 330,
+ 842, 202, 714, 458, 970, 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746, 490, 1002, 26,
+ 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858, 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954,
+ 122, 634, 378, 890, 250, 762, 506, 1018, 6, 518, 262, 774, 134, 646, 390, 902, 70, 582, 326, 838, 198, 710, 454,
+ 966, 38, 550, 294, 806, 166, 678, 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, 22, 534, 278, 790, 150, 662,
+ 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566, 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246,
+ 758, 502, 1014, 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718, 462, 974, 46, 558, 302, 814,
+ 174, 686, 430, 942, 110, 622, 366, 878, 238, 750, 494, 1006, 30, 542, 286, 798, 158, 670, 414, 926, 94, 606,
+ 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958, 126, 638, 382, 894, 254, 766, 510, 1022, 1,
+ 513, 257, 769, 129, 641, 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801, 161, 673, 417, 929,
+ 97, 609, 353, 865, 225, 737, 481, 993, 17, 529, 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465,
+ 977, 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753, 497, 1009, 9, 521, 265, 777, 137, 649,
+ 393, 905, 73, 585, 329, 841, 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617, 361, 873, 233,
+ 745, 489, 1001, 25, 537, 281, 793, 153, 665, 409, 921, 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825,
+ 185, 697, 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, 5, 517, 261, 773, 133, 645, 389, 901, 69, 581, 325,
+ 837, 197, 709, 453, 965, 37, 549, 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997, 21, 533,
+ 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725, 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117,
+ 629, 373, 885, 245, 757, 501, 1013, 13, 525, 269, 781, 141, 653, 397, 909, 77, 589, 333, 845, 205, 717, 461,
+ 973, 45, 557, 301, 813, 173, 685, 429, 941, 109, 621, 365, 877, 237, 749, 493, 1005, 29, 541, 285, 797, 157,
+ 669, 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829, 189, 701, 445, 957, 125, 637, 381, 893,
+ 253, 765, 509, 1021, 3, 515, 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963, 35, 547, 291,
+ 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739, 483, 995, 19, 531, 275, 787, 147, 659, 403, 915, 83, 595,
+ 339, 851, 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627, 371, 883, 243, 755, 499, 1011,
+ 11, 523, 267, 779, 139, 651, 395, 907, 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683, 427,
+ 939, 107, 619, 363, 875, 235, 747, 491, 1003, 27, 539, 283, 795, 155, 667, 411, 923, 91, 603, 347, 859, 219,
+ 731, 475, 987, 59, 571, 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019, 7, 519, 263, 775,
+ 135, 647, 391, 903, 71, 583, 327, 839, 199, 711, 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359,
+ 871, 231, 743, 487, 999, 23, 535, 279, 791, 151, 663, 407, 919, 87, 599, 343, 855, 215, 727, 471, 983, 55, 567,
+ 311, 823, 183, 695, 439, 951, 119, 631, 375, 887, 247, 759, 503, 1015, 15, 527, 271, 783, 143, 655, 399, 911,
+ 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815, 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495,
+ 1007, 31, 543, 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991, 63, 575, 319, 831, 191, 703,
+ 447, 959, 127, 639, 383, 895, 255, 767, 511, 1023 };
+
+ static void bitReverse(short[] poly)
+ {
+ for (int i = 0; i < Params.N; ++i)
+ {
+ int r = BitReverseTable[i];
+ if (i < r)
+ {
+ short t = poly[i];
+ poly[i] = poly[r];
+ poly[r] = t;
+ }
+ }
+ }
+
+ /*
+ * GS_bo_to_no; omegas need to be in Montgomery domain
+ */
+ static void core(short[] a, short[] omega)
+ {
+ int distance;
+ for (int i = 0; i < 10; i += 2)
+ {
+ // Even level
+ distance = 1 << i;
+ for (int start = 0; start < distance; ++start)
+ {
+ int jTwiddle = 0;
+ for (int j = start; j < Params.N - 1; j += 2 * distance)
+ {
+ int u = a[j] & 0xFFFF, v = a[j + distance] & 0xFFFF, w = omega[jTwiddle++];
+ a[j] = (short)(u + v); // Omit reduction (be lazy)
+ a[j + distance] = Reduce.montgomery(w * (u + (3 * Params.Q) - v));
+ }
+ }
+
+ // Odd level
+ distance <<= 1;
+ for (int start = 0; start < distance; ++start)
+ {
+ int jTwiddle = 0;
+ for (int j = start; j < Params.N - 1; j += 2 * distance)
+ {
+ int u = a[j] & 0xFFFF, v = a[j + distance] & 0xFFFF, w = omega[jTwiddle++];
+ a[j] = Reduce.barrett((short)(u + v));
+ a[j + distance] = Reduce.montgomery(w * (u + (3 * Params.Q) - v));
+ }
+ }
+ }
+ }
+
+ static void mulCoefficients(short[] poly, short[] factors)
+ {
+ for (int i = 0; i < Params.N; ++i)
+ {
+ int xi = poly[i] & 0xFFFF, yi = factors[i] & 0xFFFF;
+ poly[i] = Reduce.montgomery(xi * yi);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NewHope.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NewHope.java
new file mode 100644
index 00000000..7ba75d5b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/NewHope.java
@@ -0,0 +1,158 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.digests.SHA3Digest;
+
+/**
+ * This implementation is based heavily on the C reference implementation from https://cryptojedi.org/crypto/index.shtml.
+ */
+class NewHope
+{
+ private static final boolean STATISTICAL_TEST = false;
+
+ public static final int AGREEMENT_SIZE = 32;
+ public static final int POLY_SIZE = Params.N;
+ public static final int SENDA_BYTES = Params.POLY_BYTES + Params.SEED_BYTES;
+ public static final int SENDB_BYTES = Params.POLY_BYTES + Params.REC_BYTES;
+
+ public static void keygen(SecureRandom rand, byte[] send, short[] sk)
+ {
+ byte[] seed = new byte[Params.SEED_BYTES];
+ rand.nextBytes(seed);
+
+ short[] a = new short[Params.N];
+ generateA(a, seed);
+
+ byte[] noiseSeed = new byte[32];
+ rand.nextBytes(noiseSeed);
+
+ Poly.getNoise(sk, noiseSeed, (byte)0);
+ Poly.toNTT(sk);
+
+ short[] e = new short[Params.N];
+ Poly.getNoise(e, noiseSeed, (byte)1);
+ Poly.toNTT(e);
+
+ short[] r = new short[Params.N];
+ Poly.pointWise(a, sk, r);
+
+ short[] pk = new short[Params.N];
+ Poly.add(r, e, pk);
+
+ encodeA(send, pk, seed);
+ }
+
+ public static void sharedB(SecureRandom rand, byte[] sharedKey, byte[] send, byte[] received)
+ {
+ short[] pkA = new short[Params.N];
+ byte[] seed = new byte[Params.SEED_BYTES];
+ decodeA(pkA, seed, received);
+
+ short[] a = new short[Params.N];
+ generateA(a, seed);
+
+ byte[] noiseSeed = new byte[32];
+ rand.nextBytes(noiseSeed);
+
+ short[] sp = new short[Params.N];
+ Poly.getNoise(sp, noiseSeed, (byte)0);
+ Poly.toNTT(sp);
+
+ short[] ep = new short[Params.N];
+ Poly.getNoise(ep, noiseSeed, (byte)1);
+ Poly.toNTT(ep);
+
+ short[] bp = new short[Params.N];
+ Poly.pointWise(a, sp, bp);
+ Poly.add(bp, ep, bp);
+
+ short[] v = new short[Params.N];
+ Poly.pointWise(pkA, sp, v);
+ Poly.fromNTT(v);
+
+ short[] epp = new short[Params.N];
+ Poly.getNoise(epp, noiseSeed, (byte)2);
+ Poly.add(v, epp, v);
+
+ short[] c = new short[Params.N];
+ ErrorCorrection.helpRec(c, v, noiseSeed, (byte)3);
+
+ encodeB(send, bp, c);
+
+ ErrorCorrection.rec(sharedKey, v, c);
+
+ if (!STATISTICAL_TEST)
+ {
+ sha3(sharedKey);
+ }
+ }
+
+ public static void sharedA(byte[] sharedKey, short[] sk, byte[] received)
+ {
+ short[] bp = new short[Params.N];
+ short[] c = new short[Params.N];
+ decodeB(bp, c, received);
+
+ short[] v = new short[Params.N];
+ Poly.pointWise(sk, bp, v);
+ Poly.fromNTT(v);
+
+ ErrorCorrection.rec(sharedKey, v, c);
+
+ if (!STATISTICAL_TEST)
+ {
+ sha3(sharedKey);
+ }
+ }
+
+ static void decodeA(short[] pk, byte[] seed, byte[] r)
+ {
+ Poly.fromBytes(pk, r);
+ System.arraycopy(r, Params.POLY_BYTES, seed, 0, Params.SEED_BYTES);
+ }
+
+ static void decodeB(short[] b, short[] c, byte[] r)
+ {
+ Poly.fromBytes(b, r);
+
+ for (int i = 0; i < Params.N / 4; ++i)
+ {
+ int j = 4 * i;
+ int ri = r[Params.POLY_BYTES + i] & 0xFF;
+ c[j + 0] = (short)(ri & 0x03);
+ c[j + 1] = (short)((ri >>> 2) & 0x03);
+ c[j + 2] = (short)((ri >>> 4) & 0x03);
+ c[j + 3] = (short)(ri >>> 6);
+ }
+ }
+
+ static void encodeA(byte[] r, short[] pk, byte[] seed)
+ {
+ Poly.toBytes(r, pk);
+ System.arraycopy(seed, 0, r, Params.POLY_BYTES, Params.SEED_BYTES);
+ }
+
+ static void encodeB(byte[] r, short[] b, short[] c)
+ {
+ Poly.toBytes(r, b);
+
+ for (int i = 0; i < Params.N / 4; ++i)
+ {
+ int j = 4 * i;
+ r[Params.POLY_BYTES + i] = (byte)(c[j] | (c[j + 1] << 2) | (c[j + 2] << 4) | (c[j + 3] << 6));
+ }
+ }
+
+ static void generateA(short[] a, byte[] seed)
+ {
+ Poly.uniform(a, seed);
+ }
+
+ static void sha3(byte[] sharedKey)
+ {
+ SHA3Digest d = new SHA3Digest(256);
+ d.update(sharedKey, 0, 32);
+ d.doFinal(sharedKey, 0);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Params.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Params.java
new file mode 100644
index 00000000..1f13d97a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Params.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+class Params
+{
+ static final int N = 1024;
+ static final int K = 16; /* used in sampler */
+ static final int Q = 12289;
+
+ static final int POLY_BYTES = 1792;
+ static final int REC_BYTES = 256;
+ static final int SEED_BYTES = 32;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Poly.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Poly.java
new file mode 100644
index 00000000..e7228bab
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Poly.java
@@ -0,0 +1,145 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.util.Pack;
+
+class Poly
+{
+ static void add(short[] x, short[] y, short[] z)
+ {
+ for (int i = 0; i < Params.N; ++i)
+ {
+ z[i] = Reduce.barrett((short)(x[i] + y[i]));
+ }
+ }
+
+ static void fromBytes(short[] r, byte[] a)
+ {
+ for (int i = 0; i < Params.N / 4; ++i)
+ {
+ int j = 7 * i;
+ int a0 = a[j + 0] & 0xFF, a1 = a[j + 1] & 0xFF, a2 = a[j + 2] & 0xFF, a3 = a[j + 3] & 0xFF,
+ a4 = a[j + 4] & 0xFF, a5 = a[j + 5] & 0xFF, a6 = a[j + 6] & 0xFF;
+
+ int k = 4 * i;
+ r[k + 0] = (short)( a0 | ((a1 & 0x3F) << 8));
+ r[k + 1] = (short)((a1 >>> 6) | (a2 << 2) | ((a3 & 0x0F) << 10));
+ r[k + 2] = (short)((a3 >>> 4) | (a4 << 4) | ((a5 & 0x03) << 12));
+ r[k + 3] = (short)((a5 >>> 2) | (a6 << 6));
+ }
+ }
+
+ static void fromNTT(short[] r)
+ {
+ NTT.bitReverse(r);
+ NTT.core(r, Precomp.OMEGAS_INV_MONTGOMERY);
+ NTT.mulCoefficients(r, Precomp.PSIS_INV_MONTGOMERY);
+ }
+
+ static void getNoise(short[] r, byte[] seed, byte nonce)
+ {
+ byte[] iv = new byte[8];
+ iv[0] = nonce;
+
+ byte[] buf = new byte[4 * Params.N];
+ ChaCha20.process(seed, iv, buf, 0, buf.length);
+
+ for (int i = 0; i < Params.N; ++i)
+ {
+ int t = Pack.bigEndianToInt(buf, i * 4);
+ //r[i] = (short)(bitCount(t) + Params.Q - Params.K);
+
+ int d = 0;
+ for (int j = 0; j < 8; ++j)
+ {
+ d += (t >> j) & 0x01010101;
+ }
+ int a = ((d >>> 24) + (d >>> 0)) & 0xFF;
+ int b = ((d >>> 16) + (d >>> 8)) & 0xFF;
+ r[i] = (short)(a + Params.Q - b);
+ }
+ }
+
+ static void pointWise(short[] x, short[] y, short[] z)
+ {
+ for (int i = 0; i < Params.N; ++i)
+ {
+ int xi = x[i] & 0xFFFF, yi = y[i] & 0xFFFF;
+ short t = Reduce.montgomery(3186 * yi); // t is now in Montgomery domain
+ z[i] = Reduce.montgomery(xi * (t & 0xFFFF)); // z[i] is back in normal domain
+ }
+ }
+
+ static void toBytes(byte[] r, short[] p)
+ {
+ for (int i = 0; i < Params.N / 4; ++i)
+ {
+ int j = 4 * i;
+
+ // Make sure that coefficients are in [0,q]
+ short t0 = normalize(p[j + 0]);
+ short t1 = normalize(p[j + 1]);
+ short t2 = normalize(p[j + 2]);
+ short t3 = normalize(p[j + 3]);
+
+ int k = 7 * i;
+ r[k + 0] = (byte)t0;
+ r[k + 1] = (byte)((t0 >> 8) | (t1 << 6));
+ r[k + 2] = (byte)(t1 >> 2);
+ r[k + 3] = (byte)((t1 >> 10) | (t2 << 4));
+ r[k + 4] = (byte)(t2 >> 4);
+ r[k + 5] = (byte)((t2 >> 12) | (t3 << 2));
+ r[k + 6] = (byte)(t3 >> 6);
+ }
+ }
+
+ static void toNTT(short[] r)
+ {
+ NTT.mulCoefficients(r, Precomp.PSIS_BITREV_MONTGOMERY);
+ NTT.core(r, Precomp.OMEGAS_MONTGOMERY);
+ }
+
+ static void uniform(short[] a, byte[] seed)
+ {
+ SHAKEDigest xof = new SHAKEDigest(128);
+ xof.update(seed, 0, seed.length);
+
+ int pos = 0;
+ for (;;)
+ {
+ byte[] output = new byte[256];
+ xof.doOutput(output, 0, output.length);
+
+ for (int i = 0; i < output.length; i += 2)
+ {
+ int val = (output[i] & 0xFF) | ((output[i + 1] & 0xFF) << 8);
+ val &= 0x3FFF;
+ if (val < Params.Q)
+ {
+ a[pos++] = (short)val;
+ if (pos == Params.N)
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+// private static int bitCount(int n)
+// {
+//// return Integer.bitCount(n);
+// n = n - ((n >>> 1) & 0x55555555);
+// n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
+// return ((n + (n >>> 4) & 0x0F0F0F0F) * 0x01010101) >>> 24;
+// }
+
+ private static short normalize(short x)
+ {
+ int t = Reduce.barrett(x);
+ int m = t - Params.Q;
+ int c = m >> 31;
+ t = m ^ ((t ^ m) & c);
+ return (short)t;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Precomp.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Precomp.java
new file mode 100644
index 00000000..d47d5513
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Precomp.java
@@ -0,0 +1,181 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+class Precomp
+{
+ static final short[] OMEGAS_MONTGOMERY = { 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775,
+ 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449,
+ 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879,
+ 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605, 11785,
+ 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681,
+ 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, 5057, 3445,
+ 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874,
+ 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, 4774,
+ 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361, 12071,
+ 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942,
+ 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174, 2948,
+ 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570, 4240,
+ 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404, 325,
+ 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105,
+ 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726,
+ 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334,
+ 9275, 9088, 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984,
+ 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283,
+ 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525,
+ 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881,
+ 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637,
+ 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885,
+ 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002,
+ 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188,
+ 11516, 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440,
+ 8526, 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111,
+ 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777,
+ 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, 4895, 10805, 2780, 5195,
+ 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174 };
+
+ static final short[] OMEGAS_INV_MONTGOMERY = { 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278,
+ 9945, 3514, 11248, 11271, 5925, 147, 8500, 7840, 6833, 5537, 4749, 4467, 7500, 11099, 9606, 6171, 8471, 8429,
+ 5445, 11239, 7753, 9090, 12233, 5529, 5206, 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427, 7341, 6152, 10561,
+ 400, 8410, 1922, 2033, 8291, 1359, 6854, 11035, 973, 8579, 6093, 6950, 5446, 11821, 8301, 11907, 316, 52, 3174,
+ 10966, 9523, 6055, 8953, 11612, 6415, 2505, 5906, 10710, 11858, 8332, 9450, 10162, 151, 3482, 787, 5468, 1010,
+ 4169, 9162, 5241, 9369, 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, 885, 6281, 10333, 7280, 8757, 11286, 58,
+ 12048, 12147, 11184, 8812, 6608, 2844, 3438, 4212, 11314, 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507,
+ 5886, 3029, 6695, 4213, 504, 11684, 2302, 1962, 1594, 6328, 7183, 168, 2692, 8960, 4298, 5184, 11089, 6122,
+ 9734, 10929, 3956, 5297, 6170, 3762, 9370, 4016, 4077, 6523, 652, 11994, 6099, 1146, 11341, 11964, 10885, 6299,
+ 1159, 8240, 8561, 11177, 2078, 10331, 4322, 11367, 441, 4079, 11231, 3150, 1319, 8243, 709, 8049, 8719, 11454,
+ 6224, 3054, 6803, 3123, 10542, 4433, 6370, 7032, 3834, 8633, 12225, 9830, 683, 1566, 5782, 9786, 9341, 12115,
+ 723, 3009, 1693, 5735, 2655, 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, 1583, 6347, 2500,
+ 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350, 6920, 10232, 4493, 9087, 8855, 8760, 9381, 218, 9928,
+ 10446, 9259, 4115, 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, 6381, 11836, 8517, 418, 6860, 7515, 1293,
+ 7552, 2767, 156, 8298, 8320, 10008, 5876, 5333, 10258, 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689, 8236,
+ 2645, 5042, 9984, 7094, 9509, 1484, 7394, 3, 4437, 160, 3149, 113, 7370, 10123, 3915, 6998, 2704, 8653, 4938,
+ 1426, 7635, 10512, 1663, 6957, 3510, 2370, 2865, 3978, 9320, 3247, 9603, 6882, 3186, 10659, 10163, 1153, 9405,
+ 8241, 10040, 2178, 1544, 5559, 420, 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, 243, 3016, 3763,
+ 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146, 10752, 242, 2678, 3704, 11744, 5019, 3833, 3778,
+ 11899, 773, 5101, 11222, 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859, 3780, 11414, 4976, 10682,
+ 7201, 8005, 11287, 5011, 6267, 2987, 2437, 3646, 2566, 10102, 9867, 6250, 5444, 2381, 11796, 8193, 4337, 11854,
+ 1912, 1378, 404, 7644, 1065, 2143, 11121, 5277, 3248, 11082, 2548, 8058, 8907, 11934, 1759, 8582, 3694, 7110,
+ 12144, 6747, 8652, 3459, 2731, 8357, 6378, 7399, 10861, 1696, 9863, 334, 7657, 6534, 11029, 4388, 11560, 3241,
+ 10276, 9000, 9408, 3284, 10200, 7197, 6498, 544, 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, 4278, 4177,
+ 8705, 9764, 1381, 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837, 11462, 5767, 953, 8541, 9813, 118, 7222, 2197,
+ 3006, 9545, 563, 9314, 2625, 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512, 1351, 7311, 6553, 8155,
+ 1305, 722, 5146, 4043, 12288, 10810, 2545, 3621, 8747, 8785, 1646, 1212, 5860, 3195, 7203, 10963, 3201, 3014,
+ 955, 11499, 9970, 11119, 3135, 3712, 7443, 9542, 7484, 8736, 9995, 11227, 1635, 9521, 1177, 8034, 140, 10436,
+ 11563, 7678, 4320, 11289, 9198, 12208, 2963, 7393, 2366, 9238 };
+
+ static final short[] PSIS_BITREV_MONTGOMERY = { 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041,
+ 8775, 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456,
+ 4449, 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367,
+ 3879, 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605,
+ 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445,
+ 5681, 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, 5057,
+ 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784,
+ 5874, 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996,
+ 4774, 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361,
+ 12071, 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789,
+ 5942, 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174,
+ 2948, 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570,
+ 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404,
+ 325, 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105,
+ 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726,
+ 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334,
+ 9275, 9088, 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984,
+ 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283,
+ 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525,
+ 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881,
+ 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637,
+ 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885,
+ 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002,
+ 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188,
+ 11516, 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440,
+ 8526, 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111,
+ 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777,
+ 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, 4895, 10805, 2780, 5195,
+ 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174, 3947, 11951, 2455, 6599, 10545, 10975,
+ 3654, 2894, 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522, 7174, 7350, 11041, 2442, 2148, 5959, 6492, 8330,
+ 8945, 5598, 3624, 10397, 1325, 6565, 1945, 11260, 10077, 2674, 3338, 3276, 11034, 506, 6505, 1392, 5478, 8778,
+ 1178, 2776, 3408, 10347, 11124, 2575, 9489, 12096, 6092, 10058, 4167, 6085, 923, 11251, 11912, 4578, 10669,
+ 11914, 425, 10453, 392, 10104, 8464, 4235, 8761, 7376, 2291, 3375, 7954, 8896, 6617, 7790, 1737, 11667, 3982,
+ 9342, 6680, 636, 6825, 7383, 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485, 1403, 5189, 6094,
+ 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882, 8151, 180, 9600, 7684, 5219, 10880, 6780, 204, 11232, 2600,
+ 7584, 3121, 3017, 11053, 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261, 2360, 11925, 1928, 11825, 8024, 3678,
+ 3205, 3359, 11197, 5209, 8581, 3238, 8840, 1136, 9363, 1826, 3171, 4489, 7885, 346, 2068, 1389, 8257, 3163,
+ 4840, 6127, 8062, 8921, 612, 4238, 10763, 8067, 125, 11749, 10125, 5416, 2110, 716, 9839, 10584, 11475, 11873,
+ 3448, 343, 1908, 4538, 10423, 7078, 4727, 1208, 11572, 3589, 2982, 1373, 1721, 10753, 4103, 2429, 4209, 5412,
+ 5993, 9011, 438, 3515, 7228, 1218, 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566, 5836,
+ 12229, 2717, 1535, 3200, 5588, 5845, 412, 5102, 7326, 3744, 3056, 2528, 7406, 8314, 9202, 6454, 6613, 1417,
+ 10032, 7784, 1518, 3765, 4176, 5063, 9828, 2275, 6636, 4267, 6463, 2065, 7725, 3495, 8328, 8755, 8144, 10533,
+ 5966, 12077, 9175, 9520, 5596, 6302, 8400, 579, 6781, 11014, 5734, 11113, 11164, 4860, 1131, 10844, 9068, 8016,
+ 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, 682, 11309, 5207, 4050, 7087, 844, 7434, 3769, 293, 9057, 6940,
+ 9344, 10883, 2633, 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, 2213, 8136, 3805, 767, 12239, 216, 11520,
+ 6763, 10353, 7, 8566, 845, 7235, 3154, 4360, 3285, 10268, 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105, 3120,
+ 6643, 6203, 8536, 8348, 6919, 3536, 9199, 10891, 11463, 5043, 1658, 5618, 8787, 5789, 4719, 751, 11379, 6389,
+ 10783, 3065, 7806, 6586, 2622, 5386, 510, 7628, 6921, 578, 10345, 11839, 8929, 4684, 12226, 7154, 9916, 7302,
+ 8481, 3670, 11066, 2334, 1590, 7878, 10734, 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, 9996,
+ 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371, 12265, 2485, 11385, 5039, 6742, 8449, 1842,
+ 12217, 8176, 9577, 4834, 7937, 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, 5406, 4665, 3020, 6616,
+ 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038, 11249, 2035, 6125, 10407, 4565, 7315, 5078, 10506, 2840, 2478,
+ 9270, 4194, 9195, 4518, 7469, 1160, 6878, 2730, 10421, 10036, 1734, 3815, 10939, 5832, 10595, 10759, 4423, 8420,
+ 9617, 7119, 11010, 11424, 9173, 189, 10080, 10526, 3466, 10588, 7592, 3578, 11511, 7785, 9663, 530, 12150, 8957,
+ 2532, 3317, 9349, 10243, 1481, 9332, 3454, 3758, 7899, 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021,
+ 4523, 7988, 8, 457, 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462, 2873, 9855, 11498, 2535, 11169, 5808,
+ 12268, 9687, 1901, 7171, 11787, 3846, 1573, 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263, 2929 };
+
+ static final short[] PSIS_INV_MONTGOMERY = { 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000,
+ 2327, 2088, 5565, 795, 10647, 1521, 5484, 2539, 7385, 1055, 7173, 8047, 11683, 1669, 1994, 3796, 5809, 4341,
+ 9398, 11876, 12230, 10525, 12037, 12253, 3506, 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207, 5582, 2553, 7387,
+ 6322, 9681, 1383, 10731, 1533, 219, 5298, 4268, 7632, 6357, 9686, 8406, 4712, 9451, 10128, 4958, 5975, 11387,
+ 8649, 11769, 6948, 11526, 12180, 1740, 10782, 6807, 2728, 7412, 4570, 4164, 4106, 11120, 12122, 8754, 11784,
+ 3439, 5758, 11356, 6889, 9762, 11928, 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, 1991, 2040, 2047,
+ 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, 7422, 6327, 4415, 7653, 6360, 11442, 12168, 7005,
+ 8023, 9924, 8440, 8228, 2931, 7441, 1063, 3663, 5790, 9605, 10150, 1450, 8985, 11817, 10466, 10273, 12001, 3470,
+ 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367, 7789, 8135, 9940, 1420, 3714, 11064, 12114, 12264, 1752, 5517,
+ 9566, 11900, 1700, 3754, 5803, 829, 1874, 7290, 2797, 10933, 5073, 7747, 8129, 6428, 6185, 11417, 1631, 233,
+ 5300, 9535, 10140, 11982, 8734, 8270, 2937, 10953, 8587, 8249, 2934, 9197, 4825, 5956, 4362, 9401, 1343, 3703,
+ 529, 10609, 12049, 6988, 6265, 895, 3639, 4031, 4087, 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220,
+ 10095, 10220, 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379, 11159, 10372, 8504, 4726,
+ 9453, 3106, 7466, 11600, 10435, 8513, 9994, 8450, 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, 5616, 6069,
+ 867, 3635, 5786, 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794, 9177, 1311, 5454, 9557, 6632, 2703, 9164,
+ 10087, 1441, 3717, 531, 3587, 2268, 324, 5313, 759, 1864, 5533, 2546, 7386, 9833, 8427, 4715, 11207, 1601, 7251,
+ 4547, 11183, 12131, 1733, 10781, 10318, 1474, 10744, 5046, 4232, 11138, 10369, 6748, 964, 7160, 4534, 7670,
+ 8118, 8182, 4680, 11202, 6867, 981, 8918, 1274, 182, 26, 7026, 8026, 11680, 12202, 10521, 1503, 7237, 4545,
+ 5916, 9623, 8397, 11733, 10454, 3249, 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218, 6155, 6146,
+ 878, 1881, 7291, 11575, 12187, 1741, 7271, 8061, 11685, 6936, 4502, 9421, 4857, 4205, 7623, 1089, 10689, 1527,
+ 8996, 10063, 11971, 10488, 6765, 2722, 3900, 9335, 11867, 6962, 11528, 5158, 4248, 4118, 5855, 2592, 5637, 6072,
+ 2623, 7397, 8079, 9932, 4930, 5971, 853, 3633, 519, 8852, 11798, 3441, 11025, 1575, 225, 8810, 11792, 12218,
+ 3501, 9278, 3081, 9218, 4828, 7712, 8124, 11694, 12204, 3499, 4011, 573, 3593, 5780, 7848, 9899, 10192, 1456,
+ 208, 7052, 2763, 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, 7841, 9898, 1414, 202, 3540, 7528,
+ 2831, 2160, 10842, 5060, 4234, 4116, 588, 84, 12, 7024, 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457, 6332,
+ 11438, 1634, 1989, 9062, 11828, 8712, 11778, 12216, 10523, 6770, 9745, 10170, 4964, 9487, 6622, 946, 8913, 6540,
+ 6201, 4397, 9406, 8366, 9973, 8447, 8229, 11709, 8695, 10020, 3187, 5722, 2573, 10901, 6824, 4486, 4152, 9371,
+ 8361, 2950, 2177, 311, 1800, 9035, 8313, 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, 11609, 3414, 7510,
+ 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, 9815, 10180, 6721, 9738, 10169, 8475, 8233, 9954, 1422,
+ 8981, 1283, 5450, 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704, 672, 96, 7036, 9783,
+ 11931, 3460, 5761, 823, 10651, 12055, 10500, 1500, 5481, 783, 3623, 11051, 8601, 8251, 8201, 11705, 10450, 5004,
+ 4226, 7626, 2845, 2162, 3820, 7568, 9859, 3164, 452, 10598, 1514, 5483, 6050, 6131, 4387, 7649, 8115, 6426, 918,
+ 8909, 8295, 1185, 5436, 11310, 8638, 1234, 5443, 11311, 5127, 2488, 2111, 10835, 5059, 7745, 2862, 3920, 560,
+ 80, 1767, 2008, 3798, 11076, 6849, 2734, 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, 4786,
+ 7706, 4612, 4170, 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733, 4473, 639, 5358, 2521, 9138, 3061, 5704,
+ 4326, 618, 5355, 765, 5376, 768, 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266, 12000, 6981, 6264,
+ 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165, 9230, 11852, 10471, 5007, 5982, 11388, 5138, 734, 3616, 11050,
+ 12112, 6997, 11533, 12181, 10518, 12036, 3475, 2252, 7344, 9827, 4915, 9480, 6621, 4457, 7659, 9872, 6677, 4465,
+ 4149, 7615, 4599, 657, 3605, 515, 10607, 6782, 4480, 640, 1847, 3775, 5806, 2585, 5636, 9583, 1369, 10729, 8555,
+ 10000, 11962, 5220, 7768, 8132, 8184, 9947, 1421, 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378,
+ 4708, 11206, 5112, 5997, 7879, 11659, 12199, 8765, 10030, 4944, 5973, 6120, 6141, 6144, 7900, 11662, 1666, 238,
+ 34, 3516, 5769, 9602, 8394, 9977, 6692, 956, 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742, 106, 8793, 10034,
+ 3189, 10989, 5081, 4237, 5872, 4350, 2377, 10873, 6820, 6241, 11425, 10410, 10265, 3222, 5727, 9596, 4882, 2453,
+ 2106, 3812, 11078, 12116, 5242, 4260, 11142, 8614, 11764, 12214, 5256, 4262, 4120, 11122, 5100, 11262, 5120,
+ 2487, 5622, 9581, 8391, 8221, 2930, 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, 4027, 5842, 11368, 1624,
+ 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, 797, 3625, 4029, 11109, 1587, 7249, 11569, 8675, 6506, 2685,
+ 10917, 12093, 12261, 12285, 1755, 7273, 1039, 1904, 272, 3550, 9285, 3082, 5707, 6082, 4380, 7648, 11626, 5172,
+ 4250, 9385, 8363, 8217, 4685, 5936, 848, 8899, 6538, 934, 1889, 3781, 9318, 10109, 10222, 6727, 961, 5404, 772,
+ 5377, 9546, 8386, 1198, 8949, 3034, 2189, 7335, 4559, 5918, 2601, 10905, 5069, 9502, 3113, 7467, 8089, 11689,
+ 5181, 9518, 8382, 2953, 3933, 4073, 4093, 7607, 8109, 2914, 5683, 4323, 11151, 1593, 10761, 6804, 972, 3650,
+ 2277, 5592, 4310, 7638, 9869, 4921, 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, 6376, 4422,
+ 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721, 12065, 12257, 1751, 9028, 8312, 2943, 2176, 3822,
+ 546, 78, 8789, 11789, 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, 613, 10621, 6784, 9747, 3148, 7472,
+ 2823, 5670, 810, 7138, 8042, 4660, 7688, 6365, 6176, 6149, 2634, 5643, 9584, 10147, 11983, 5223, 9524, 11894,
+ 10477, 8519, 1217, 3685, 2282, 326, 10580, 3267, 7489, 4581, 2410, 5611, 11335, 6886, 8006, 8166, 11700, 3427,
+ 11023, 8597, 10006, 3185, 455, 65, 5276, 7776, 4622, 5927, 7869, 9902, 11948, 5218, 2501, 5624, 2559, 10899,
+ 1557, 1978, 10816, 10323, 8497, 4725, 675, 1852, 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083,
+ 10504, 12034, 10497 };
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Reduce.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Reduce.java
new file mode 100644
index 00000000..d71e1edd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/newhope/Reduce.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.pqc.crypto.newhope;
+
+class Reduce
+{
+ static final int QInv = 12287; // -inverse_mod(p,2^18)
+ static final int RLog = 18;
+ static final int RMask = (1 << RLog) - 1;
+
+ static short montgomery(int a)
+ {
+ int u = a * QInv;
+ u &= RMask;
+ u *= Params.Q;
+ u += a;
+ return (short)(u >>> RLog);
+ }
+
+ static short barrett(short a)
+ {
+ int t = a & 0xFFFF;
+ int u = (t * 5) >>> 16;
+ u *= Params.Q;
+ return (short)(t - u);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java
index 8d64ae29..74267246 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java
@@ -195,7 +195,7 @@ public class NTRUEncryptionKeyGenerationParameters
minCallsMask = dis.readInt();
hashSeed = dis.readBoolean();
oid = new byte[3];
- dis.read(oid);
+ dis.readFully(oid);
sparse = dis.readBoolean();
fastFp = dis.readBoolean();
polyType = dis.read();
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/HashFunctions.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/HashFunctions.java
new file mode 100644
index 00000000..9bad9554
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/HashFunctions.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.util.Strings;
+
+
+class HashFunctions
+{
+ private static final byte[] hashc = Strings.toByteArray("expand 32-byte to 64-byte state!");
+
+ private final Digest dig256;
+ private final Digest dig512;
+ private final Permute perm = new Permute();
+
+ // for key pair generation where message hash not required
+ HashFunctions(Digest dig256)
+ {
+ this(dig256, null);
+ }
+
+ HashFunctions(Digest dig256, Digest dig512)
+ {
+ this.dig256 = dig256;
+ this.dig512 = dig512;
+ }
+
+ int varlen_hash(byte[] out, int outOff, byte[] in, int inLen)
+ {
+ dig256.update(in, 0, inLen);
+
+ dig256.doFinal(out, outOff);
+
+ return 0;
+ }
+
+ Digest getMessageHash()
+ {
+ return dig512;
+ }
+
+ int hash_2n_n(byte[] out, int outOff, byte[] in, int inOff)
+ {
+ byte[] x = new byte[64];
+ int i;
+ for (i = 0; i < 32; i++)
+ {
+ x[i] = in[inOff + i];
+ x[i + 32] = hashc[i];
+ }
+ perm.chacha_permute(x, x);
+ for (i = 0; i < 32; i++)
+ {
+ x[i] = (byte)(x[i] ^ in[inOff + i + 32]);
+ }
+ perm.chacha_permute(x, x);
+ for (i = 0; i < 32; i++)
+ {
+ out[outOff + i] = x[i];
+ }
+
+ return 0;
+ }
+
+ int hash_2n_n_mask(byte[] out, int outOff, byte[] in, int inOff, byte[] mask, int maskOff)
+ {
+ byte[] buf = new byte[2 * SPHINCS256Config.HASH_BYTES];
+ int i;
+ for (i = 0; i < 2 * SPHINCS256Config.HASH_BYTES; i++)
+ {
+ buf[i] = (byte)(in[inOff + i] ^ mask[maskOff + i]);
+ }
+
+ int rv = hash_2n_n(out, outOff, buf, 0);
+
+ return rv;
+ }
+
+ int hash_n_n(byte[] out, int outOff, byte[] in, int inOff)
+ {
+
+ byte[] x = new byte[64];
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ x[i] = in[inOff + i];
+ x[i + 32] = hashc[i];
+ }
+ perm.chacha_permute(x, x);
+ for (i = 0; i < 32; i++)
+ {
+ out[outOff + i] = x[i];
+ }
+
+ return 0;
+ }
+
+ int hash_n_n_mask(byte[] out, int outOff, byte[] in, int inOff, byte[] mask, int maskOff)
+ {
+ byte[] buf = new byte[SPHINCS256Config.HASH_BYTES];
+ int i;
+ for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
+ {
+ buf[i] = (byte)(in[inOff + i] ^ mask[maskOff + i]);
+ }
+ return hash_n_n(out, outOff, buf, 0);
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Horst.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Horst.java
new file mode 100644
index 00000000..a24341d3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Horst.java
@@ -0,0 +1,179 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+class Horst
+{
+ static final int HORST_LOGT = 16;
+ static final int HORST_T = (1<<HORST_LOGT);
+ static final int HORST_K = 32;
+ static final int HORST_SKBYTES = 32;
+ static final int HORST_SIGBYTES = (64* SPHINCS256Config.HASH_BYTES+(((HORST_LOGT-6)* SPHINCS256Config.HASH_BYTES)+HORST_SKBYTES)*HORST_K);
+
+ static final int N_MASKS = (2*(Horst.HORST_LOGT)); /* has to be the max of (2*(SUBTREE_HEIGHT+WOTS_LOGL)) and (WOTS_W-1) and 2*HORST_LOGT */
+
+ static void expand_seed(byte[] outseeds, byte[] inseed)
+ {
+ Seed.prg(outseeds, 0, HORST_T * HORST_SKBYTES, inseed, 0);
+ }
+
+ static int horst_sign(HashFunctions hs,
+ byte[] sig, int sigOff, byte[] pk,
+ byte[] seed,
+ byte[] masks,
+ byte[] m_hash)
+ {
+ byte[] sk = new byte[ HORST_T * HORST_SKBYTES];
+ int idx;
+ int i, j, k;
+ int sigpos = sigOff;
+
+ byte[] tree = new byte[(2 * HORST_T - 1) * SPHINCS256Config.HASH_BYTES]; /* replace by something more memory-efficient? */
+
+ expand_seed(sk, seed);
+
+ // Build the whole tree and save it
+
+ // Generate pk leaves
+ for (i = 0; i < HORST_T; i++)
+ {
+ hs.hash_n_n(tree, (HORST_T - 1 + i) * SPHINCS256Config.HASH_BYTES, sk, i * HORST_SKBYTES);
+ }
+
+ long offset_in, offset_out;
+ for (i = 0; i < HORST_LOGT; i++)
+ {
+ offset_in = (1 << (HORST_LOGT - i)) - 1;
+ offset_out = (1 << (HORST_LOGT - i - 1)) - 1;
+ for (j = 0; j < (1 << (HORST_LOGT - i - 1)); j++)
+ {
+ hs.hash_2n_n_mask(tree, (int)((offset_out + j) * SPHINCS256Config.HASH_BYTES), tree, (int)((offset_in + 2 * j) * SPHINCS256Config.HASH_BYTES), masks, 2 * i * SPHINCS256Config.HASH_BYTES);
+ }
+ }
+
+ // First write 64 hashes from level 10 to the signature
+ for (j = 63 * SPHINCS256Config.HASH_BYTES; j < 127 * SPHINCS256Config.HASH_BYTES; j++)
+ {
+ sig[sigpos++] = tree[j];
+ }
+
+ // Signature consists of HORST_K parts; each part of secret key and HORST_LOGT-4 auth-path hashes
+ for (i = 0; i < HORST_K; i++)
+ {
+ idx = (m_hash[2 * i] & 0xff) + ((m_hash[2 * i + 1] & 0xff) << 8);
+
+ for (k = 0; k < HORST_SKBYTES; k++)
+ sig[sigpos++] = sk[idx * HORST_SKBYTES + k];
+
+ idx += (HORST_T - 1);
+ for (j = 0; j < HORST_LOGT - 6; j++)
+ {
+ idx = ((idx & 1) != 0) ? idx + 1 : idx - 1; // neighbor node
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ sig[sigpos++] = tree[idx * SPHINCS256Config.HASH_BYTES + k];
+ idx = (idx - 1) / 2; // parent node
+ }
+ }
+
+ for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
+ {
+ pk[i] = tree[i];
+ }
+
+ return HORST_SIGBYTES;
+ }
+
+ static int horst_verify(HashFunctions hs, byte[] pk, byte[] sig, int sigOff, byte[] masks, byte[] m_hash)
+ {
+ byte[] buffer = new byte[ 32 * SPHINCS256Config.HASH_BYTES];
+
+ int idx;
+ int i, j, k;
+
+ int sigOffset = sigOff + 64 * SPHINCS256Config.HASH_BYTES;
+
+ for (i = 0; i < HORST_K; i++)
+ {
+ idx = (m_hash[2 * i] & 0xff) + ((m_hash[2 * i + 1] & 0xff) << 8);
+
+ if ((idx & 1) == 0)
+ {
+ hs.hash_n_n(buffer, 0, sig, sigOffset);
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ buffer[SPHINCS256Config.HASH_BYTES + k] = sig[sigOffset + HORST_SKBYTES + k];
+ }
+ else
+ {
+ hs.hash_n_n(buffer, SPHINCS256Config.HASH_BYTES, sig, sigOffset);
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ buffer[k] = sig[sigOffset + HORST_SKBYTES + k];
+ }
+ sigOffset += HORST_SKBYTES + SPHINCS256Config.HASH_BYTES;
+
+ for (j = 1; j < HORST_LOGT - 6; j++)
+ {
+ idx = idx >>> 1; // parent node
+
+ if ((idx & 1) == 0)
+ {
+ hs.hash_2n_n_mask(buffer, 0, buffer, 0, masks, 2 * (j - 1) * SPHINCS256Config.HASH_BYTES);
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ buffer[SPHINCS256Config.HASH_BYTES + k] = sig[sigOffset + k];
+ }
+ else
+ {
+
+ hs.hash_2n_n_mask(buffer, SPHINCS256Config.HASH_BYTES, buffer, 0, masks, 2 * (j - 1) * SPHINCS256Config.HASH_BYTES);
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ buffer[k] = sig[sigOffset + k];
+ }
+ sigOffset += SPHINCS256Config.HASH_BYTES;
+ }
+
+ idx = idx >>> 1; // parent node
+ hs.hash_2n_n_mask(buffer, 0, buffer, 0, masks, 2 * (HORST_LOGT - 7) * SPHINCS256Config.HASH_BYTES);
+
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ if (sig[sigOff + idx * SPHINCS256Config.HASH_BYTES + k] != buffer[k])
+ {
+ for (k = 0; k < SPHINCS256Config.HASH_BYTES; k++)
+ pk[k] = 0;
+ return -1;
+ }
+ }
+
+ // Compute root from level10
+ for (j = 0; j < 32; j++)
+ {
+ hs.hash_2n_n_mask(buffer, j * SPHINCS256Config.HASH_BYTES, sig, sigOff + 2 * j * SPHINCS256Config.HASH_BYTES, masks, 2 * (HORST_LOGT - 6) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ // Hash from level 11 to 12
+ for (j = 0; j < 16; j++)
+ {
+ hs.hash_2n_n_mask(buffer, j * SPHINCS256Config.HASH_BYTES, buffer, 2 * j * SPHINCS256Config.HASH_BYTES, masks, 2 * (HORST_LOGT - 5) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ // Hash from level 12 to 13
+ for (j = 0; j < 8; j++)
+ {
+ hs.hash_2n_n_mask(buffer, j * SPHINCS256Config.HASH_BYTES, buffer, 2 * j * SPHINCS256Config.HASH_BYTES, masks, 2 * (HORST_LOGT - 4) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ // Hash from level 13 to 14
+ for (j = 0; j < 4; j++)
+ {
+ hs.hash_2n_n_mask(buffer, j * SPHINCS256Config.HASH_BYTES, buffer, 2 * j * SPHINCS256Config.HASH_BYTES, masks, 2 * (HORST_LOGT - 3) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ // Hash from level 14 to 15
+ for (j = 0; j < 2; j++)
+ {
+ hs.hash_2n_n_mask(buffer, j * SPHINCS256Config.HASH_BYTES, buffer, 2 * j * SPHINCS256Config.HASH_BYTES, masks, 2 * (HORST_LOGT - 2) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ // Hash from level 15 to 16
+ hs.hash_2n_n_mask(pk, 0, buffer, 0, masks, 2 * (HORST_LOGT - 1) * SPHINCS256Config.HASH_BYTES);
+
+ return 0;
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Permute.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Permute.java
new file mode 100644
index 00000000..0dadfb41
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Permute.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import org.bouncycastle.util.Pack;
+
+class Permute
+{
+ private static final int CHACHA_ROUNDS = 12;
+
+
+ protected static int rotl(int x, int y)
+ {
+ return (x << y) | (x >>> -y);
+ }
+
+ /**
+ * ChaCha core function
+ */
+ public static void permute(int rounds, int[] x)
+ {
+ if (x.length != 16)
+ {
+ throw new IllegalArgumentException();
+ }
+ if (rounds % 2 != 0)
+ {
+ throw new IllegalArgumentException("Number of rounds must be even");
+ }
+
+ int x00 = x[ 0];
+ int x01 = x[ 1];
+ int x02 = x[ 2];
+ int x03 = x[ 3];
+ int x04 = x[ 4];
+ int x05 = x[ 5];
+ int x06 = x[ 6];
+ int x07 = x[ 7];
+ int x08 = x[ 8];
+ int x09 = x[ 9];
+ int x10 = x[10];
+ int x11 = x[11];
+ int x12 = x[12];
+ int x13 = x[13];
+ int x14 = x[14];
+ int x15 = x[15];
+
+ for (int i = rounds; i > 0; i -= 2)
+ {
+ x00 += x04; x12 = rotl(x12 ^ x00, 16);
+ x08 += x12; x04 = rotl(x04 ^ x08, 12);
+ x00 += x04; x12 = rotl(x12 ^ x00, 8);
+ x08 += x12; x04 = rotl(x04 ^ x08, 7);
+ x01 += x05; x13 = rotl(x13 ^ x01, 16);
+ x09 += x13; x05 = rotl(x05 ^ x09, 12);
+ x01 += x05; x13 = rotl(x13 ^ x01, 8);
+ x09 += x13; x05 = rotl(x05 ^ x09, 7);
+ x02 += x06; x14 = rotl(x14 ^ x02, 16);
+ x10 += x14; x06 = rotl(x06 ^ x10, 12);
+ x02 += x06; x14 = rotl(x14 ^ x02, 8);
+ x10 += x14; x06 = rotl(x06 ^ x10, 7);
+ x03 += x07; x15 = rotl(x15 ^ x03, 16);
+ x11 += x15; x07 = rotl(x07 ^ x11, 12);
+ x03 += x07; x15 = rotl(x15 ^ x03, 8);
+ x11 += x15; x07 = rotl(x07 ^ x11, 7);
+ x00 += x05; x15 = rotl(x15 ^ x00, 16);
+ x10 += x15; x05 = rotl(x05 ^ x10, 12);
+ x00 += x05; x15 = rotl(x15 ^ x00, 8);
+ x10 += x15; x05 = rotl(x05 ^ x10, 7);
+ x01 += x06; x12 = rotl(x12 ^ x01, 16);
+ x11 += x12; x06 = rotl(x06 ^ x11, 12);
+ x01 += x06; x12 = rotl(x12 ^ x01, 8);
+ x11 += x12; x06 = rotl(x06 ^ x11, 7);
+ x02 += x07; x13 = rotl(x13 ^ x02, 16);
+ x08 += x13; x07 = rotl(x07 ^ x08, 12);
+ x02 += x07; x13 = rotl(x13 ^ x02, 8);
+ x08 += x13; x07 = rotl(x07 ^ x08, 7);
+ x03 += x04; x14 = rotl(x14 ^ x03, 16);
+ x09 += x14; x04 = rotl(x04 ^ x09, 12);
+ x03 += x04; x14 = rotl(x14 ^ x03, 8);
+ x09 += x14; x04 = rotl(x04 ^ x09, 7);
+ }
+
+ x[ 0] = x00;
+ x[ 1] = x01;
+ x[ 2] = x02;
+ x[ 3] = x03;
+ x[ 4] = x04;
+ x[ 5] = x05;
+ x[ 6] = x06;
+ x[ 7] = x07;
+ x[ 8] = x08;
+ x[ 9] = x09;
+ x[10] = x10;
+ x[11] = x11;
+ x[12] = x12;
+ x[13] = x13;
+ x[14] = x14;
+ x[15] = x15;
+ }
+
+ void chacha_permute(byte[] out, byte[] in)
+ {
+ int i;
+
+ int[] x = new int[16];
+ for (i = 0; i < 16; i++)
+ {
+ x[i] = Pack.littleEndianToInt(in, 4 * i);
+ }
+
+ permute(CHACHA_ROUNDS, x);
+
+ // for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]); // XXX: Bad idea if we later xor the input to the state?
+ for (i = 0; i < 16; ++i)
+ {
+ Pack.intToLittleEndian(x[i], out, 4 * i);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Config.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Config.java
new file mode 100644
index 00000000..5fc0b68b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Config.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+class SPHINCS256Config
+{
+ static final int SUBTREE_HEIGHT = 5;
+ static final int TOTALTREE_HEIGHT = 60;
+ static final int N_LEVELS = (TOTALTREE_HEIGHT / SUBTREE_HEIGHT);
+ static final int SEED_BYTES = 32;
+
+ static final int SK_RAND_SEED_BYTES = 32;
+ static final int MESSAGE_HASH_SEED_BYTES = 32;
+
+ static final int HASH_BYTES = 32; // Has to be log(HORST_T)*HORST_K/8
+ static final int MSGHASH_BYTES = 64;
+
+ static final int CRYPTO_PUBLICKEYBYTES = ((Horst.N_MASKS + 1) * HASH_BYTES);
+ static final int CRYPTO_SECRETKEYBYTES = (SEED_BYTES + CRYPTO_PUBLICKEYBYTES - HASH_BYTES + SK_RAND_SEED_BYTES);
+ static final int CRYPTO_BYTES = (MESSAGE_HASH_SEED_BYTES + (TOTALTREE_HEIGHT + 7) / 8 + Horst.HORST_SIGBYTES + (TOTALTREE_HEIGHT / SUBTREE_HEIGHT) * Wots.WOTS_SIGBYTES + TOTALTREE_HEIGHT * HASH_BYTES);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyGenerationParameters.java
new file mode 100644
index 00000000..cf10a7ee
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyGenerationParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class SPHINCS256KeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private final Digest treeDigest;
+
+ public SPHINCS256KeyGenerationParameters(SecureRandom random, Digest treeDigest)
+ {
+ super(random, SPHINCS256Config.CRYPTO_PUBLICKEYBYTES * 8);
+ this.treeDigest = treeDigest;
+ }
+
+ public Digest getTreeDigest()
+ {
+ return treeDigest;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java
new file mode 100644
index 00000000..9186c04c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class SPHINCS256KeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private SecureRandom random;
+ private Digest treeDigest;
+
+ public void init(KeyGenerationParameters param)
+ {
+ random = param.getRandom();
+ treeDigest = ((SPHINCS256KeyGenerationParameters)param).getTreeDigest();
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ Tree.leafaddr a = new Tree.leafaddr();
+
+ byte[] sk = new byte[SPHINCS256Config.CRYPTO_SECRETKEYBYTES];
+
+ random.nextBytes(sk);
+
+ byte[] pk = new byte[SPHINCS256Config.CRYPTO_PUBLICKEYBYTES];
+
+ System.arraycopy(sk, SPHINCS256Config.SEED_BYTES, pk, 0, Horst.N_MASKS * SPHINCS256Config.HASH_BYTES);
+
+ // Initialization of top-subtree address
+ a.level = SPHINCS256Config.N_LEVELS - 1;
+ a.subtree = 0;
+ a.subleaf = 0;
+
+ HashFunctions hs = new HashFunctions(treeDigest);
+
+ // Format pk: [|N_MASKS*params.HASH_BYTES| Bitmasks || root]
+ // Construct top subtree
+ Tree.treehash(hs, pk, (Horst.N_MASKS * SPHINCS256Config.HASH_BYTES), SPHINCS256Config.SUBTREE_HEIGHT, sk, a, pk, 0);
+
+ return new AsymmetricCipherKeyPair(new SPHINCSPublicKeyParameters(pk), new SPHINCSPrivateKeyParameters(sk));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java
new file mode 100644
index 00000000..c15f48a4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java
@@ -0,0 +1,404 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.pqc.crypto.MessageSigner;
+import org.bouncycastle.util.Pack;
+
+/**
+ * SPHINCS-256 signer.
+ * <p>
+ * This implementation is heavily based on the reference implementation in SUPERCOP, the main difference being the digests used
+ * for message hashing and tree construction are now configurable (within limits...) and that the implementation produces
+ * detached signatures.
+ * </p>
+ */
+public class SPHINCS256Signer
+ implements MessageSigner
+{
+ private final HashFunctions hashFunctions;
+
+ private byte[] keyData;
+
+ /**
+ * Base constructor.
+ *
+ * @param nDigest the "n-digest" must produce 32 bytes of output - used for tree construction.
+ * @param twoNDigest the "2n-digest" must produce 64 bytes of output - used for initial message/key/seed hashing.
+ */
+ public SPHINCS256Signer(Digest nDigest, Digest twoNDigest)
+ {
+ if (nDigest.getDigestSize() != 32)
+ {
+ throw new IllegalArgumentException("n-digest needs to produce 32 bytes of output");
+ }
+ if (twoNDigest.getDigestSize() != 64)
+ {
+ throw new IllegalArgumentException("2n-digest needs to produce 64 bytes of output");
+ }
+
+ this.hashFunctions = new HashFunctions(nDigest, twoNDigest);
+ }
+
+ public void init(boolean forSigning, CipherParameters param)
+ {
+ if (forSigning)
+ {
+ keyData = ((SPHINCSPrivateKeyParameters)param).getKeyData();
+ }
+ else
+ {
+ keyData = ((SPHINCSPublicKeyParameters)param).getKeyData();
+ }
+ }
+
+ public byte[] generateSignature(byte[] message)
+ {
+ return crypto_sign(hashFunctions, message, keyData);
+ }
+
+ public boolean verifySignature(byte[] message, byte[] signature)
+ {
+ return verify(hashFunctions, message, signature, keyData);
+ }
+
+ static void validate_authpath(HashFunctions hs, byte[] root, byte[] leaf, int leafidx, byte[] authpath, int auOff, byte[] masks, int height)
+ {
+ int i, j;
+ byte[] buffer = new byte[2 * SPHINCS256Config.HASH_BYTES];
+
+ if ((leafidx & 1) != 0)
+ {
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[SPHINCS256Config.HASH_BYTES + j] = leaf[j];
+ }
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[j] = authpath[auOff + j];
+ }
+ }
+ else
+ {
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[j] = leaf[j];
+ }
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[SPHINCS256Config.HASH_BYTES + j] = authpath[auOff + j];
+ }
+ }
+ int authOff = auOff + SPHINCS256Config.HASH_BYTES;
+
+ for (i = 0; i < height - 1; i++)
+ {
+ leafidx >>>= 1;
+ if ((leafidx & 1) != 0)
+ {
+ hs.hash_2n_n_mask(buffer, SPHINCS256Config.HASH_BYTES, buffer, 0, masks, 2 * (Wots.WOTS_LOG_L + i) * SPHINCS256Config.HASH_BYTES);
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[j] = authpath[authOff + j];
+ }
+ }
+ else
+ {
+ hs.hash_2n_n_mask(buffer, 0, buffer, 0, masks, 2 * (Wots.WOTS_LOG_L + i) * SPHINCS256Config.HASH_BYTES);
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ {
+ buffer[j + SPHINCS256Config.HASH_BYTES] = authpath[authOff + j];
+ }
+ }
+ authOff += SPHINCS256Config.HASH_BYTES;
+ }
+ hs.hash_2n_n_mask(root, 0, buffer, 0, masks, 2 * (Wots.WOTS_LOG_L + height - 1) * SPHINCS256Config.HASH_BYTES);
+ }
+
+
+ static void compute_authpath_wots(HashFunctions hs, byte[] root, byte[] authpath, int authOff, Tree.leafaddr a, byte[] sk, byte[] masks, int height)
+ {
+ int i, idx, j;
+ Tree.leafaddr ta = new Tree.leafaddr(a);
+
+ byte[] tree = new byte[2 * (1 << SPHINCS256Config.SUBTREE_HEIGHT) * SPHINCS256Config.HASH_BYTES];
+ byte[] seed = new byte[(1 << SPHINCS256Config.SUBTREE_HEIGHT) * SPHINCS256Config.SEED_BYTES];
+ byte[] pk = new byte[(1 << SPHINCS256Config.SUBTREE_HEIGHT) * Wots.WOTS_L * SPHINCS256Config.HASH_BYTES];
+
+ // level 0
+ for (ta.subleaf = 0; ta.subleaf < (1 << SPHINCS256Config.SUBTREE_HEIGHT); ta.subleaf++)
+ {
+ Seed.get_seed(hs, seed, (int)(ta.subleaf * SPHINCS256Config.SEED_BYTES), sk, ta);
+ }
+
+ Wots w = new Wots();
+
+ for (ta.subleaf = 0; ta.subleaf < (1 << SPHINCS256Config.SUBTREE_HEIGHT); ta.subleaf++)
+ {
+ w.wots_pkgen(hs, pk, (int)(ta.subleaf * Wots.WOTS_L * SPHINCS256Config.HASH_BYTES), seed, (int)(ta.subleaf * SPHINCS256Config.SEED_BYTES), masks, 0);
+ }
+
+ for (ta.subleaf = 0; ta.subleaf < (1 << SPHINCS256Config.SUBTREE_HEIGHT); ta.subleaf++)
+ {
+ Tree.l_tree(hs, tree, (int)((1 << SPHINCS256Config.SUBTREE_HEIGHT) * SPHINCS256Config.HASH_BYTES + ta.subleaf * SPHINCS256Config.HASH_BYTES),
+ pk, (int)(ta.subleaf * Wots.WOTS_L * SPHINCS256Config.HASH_BYTES), masks, 0);
+ }
+
+ int level = 0;
+
+ // tree
+ for (i = (1 << SPHINCS256Config.SUBTREE_HEIGHT); i > 0; i >>>= 1)
+ {
+ for (j = 0; j < i; j += 2)
+ {
+ hs.hash_2n_n_mask(tree, (i >>> 1) * SPHINCS256Config.HASH_BYTES + (j >>> 1) * SPHINCS256Config.HASH_BYTES,
+ tree, i * SPHINCS256Config.HASH_BYTES + j * SPHINCS256Config.HASH_BYTES,
+ masks, 2 * (Wots.WOTS_LOG_L + level) * SPHINCS256Config.HASH_BYTES);
+ }
+
+ level++;
+ }
+
+
+ idx = (int)a.subleaf;
+
+ // copy authpath
+ for (i = 0; i < height; i++)
+ {
+ System.arraycopy(tree, ((1 << SPHINCS256Config.SUBTREE_HEIGHT) >>> i) * SPHINCS256Config.HASH_BYTES + ((idx >>> i) ^ 1) * SPHINCS256Config.HASH_BYTES, authpath, authOff + i * SPHINCS256Config.HASH_BYTES, SPHINCS256Config.HASH_BYTES);
+ }
+
+ // copy root
+ System.arraycopy(tree, SPHINCS256Config.HASH_BYTES, root, 0, SPHINCS256Config.HASH_BYTES);
+ }
+
+ byte[] crypto_sign(HashFunctions hs, byte[] m, byte[] sk)
+ {
+ byte[] sm = new byte[SPHINCS256Config.CRYPTO_BYTES];
+
+ int i;
+ long leafidx;
+ byte[] R = new byte[SPHINCS256Config.MESSAGE_HASH_SEED_BYTES];
+ byte[] m_h = new byte[SPHINCS256Config.MSGHASH_BYTES];
+ long[] rnd = new long[8];
+
+ byte[] root = new byte[SPHINCS256Config.HASH_BYTES];
+ byte[] seed = new byte[SPHINCS256Config.SEED_BYTES];
+ byte[] masks = new byte[Horst.N_MASKS * SPHINCS256Config.HASH_BYTES];
+ int pk;
+ byte[] tsk = new byte[SPHINCS256Config.CRYPTO_SECRETKEYBYTES];
+
+ for (i = 0; i < SPHINCS256Config.CRYPTO_SECRETKEYBYTES; i++)
+ {
+ tsk[i] = sk[i];
+ }
+
+ // create leafidx deterministically
+ {
+ // shift scratch upwards so we can reuse msg later
+ int scratch = SPHINCS256Config.CRYPTO_BYTES - SPHINCS256Config.SK_RAND_SEED_BYTES;
+
+ // Copy secret random seed to scratch
+ System.arraycopy(tsk, SPHINCS256Config.CRYPTO_SECRETKEYBYTES - SPHINCS256Config.SK_RAND_SEED_BYTES, sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);
+
+ Digest d = hs.getMessageHash();
+ byte[] bRnd = new byte[d.getDigestSize()];
+
+ d.update(sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);
+
+ d.update(m, 0, m.length);
+
+ d.doFinal(bRnd, 0);
+
+ // wipe sk
+ zerobytes(sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);
+
+ for (int j = 0; j != rnd.length; j++)
+ {
+ rnd[j] = Pack.littleEndianToLong(bRnd, j * 8);
+ }
+ leafidx = rnd[0] & 0xfffffffffffffffL;
+
+ System.arraycopy(bRnd, 16, R, 0, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);
+
+ // prepare msg_hash
+ scratch = SPHINCS256Config.CRYPTO_BYTES - SPHINCS256Config.MESSAGE_HASH_SEED_BYTES - SPHINCS256Config.CRYPTO_PUBLICKEYBYTES;
+
+ // cpy R
+ System.arraycopy(R, 0, sm, scratch, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);
+
+ // construct and cpy pk
+ Tree.leafaddr b = new Tree.leafaddr();
+ b.level = SPHINCS256Config.N_LEVELS - 1;
+ b.subtree = 0;
+ b.subleaf = 0;
+
+ pk = scratch + SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;
+
+ System.arraycopy(tsk, SPHINCS256Config.SEED_BYTES, sm, pk, Horst.N_MASKS * SPHINCS256Config.HASH_BYTES);
+
+ Tree.treehash(hs, sm, pk + (Horst.N_MASKS * SPHINCS256Config.HASH_BYTES), SPHINCS256Config.SUBTREE_HEIGHT, tsk, b, sm, pk);
+
+ d = hs.getMessageHash();
+
+ d.update(sm, scratch, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES + SPHINCS256Config.CRYPTO_PUBLICKEYBYTES);
+ d.update(m, 0, m.length);
+ d.doFinal(m_h, 0);
+ }
+
+ Tree.leafaddr a = new Tree.leafaddr();
+
+ a.level = SPHINCS256Config.N_LEVELS; // Use unique value $d$ for HORST address.
+ a.subleaf = (int)(leafidx & ((1 << SPHINCS256Config.SUBTREE_HEIGHT) - 1));
+ a.subtree = leafidx >>> SPHINCS256Config.SUBTREE_HEIGHT;
+
+ for (i = 0; i < SPHINCS256Config.MESSAGE_HASH_SEED_BYTES; i++)
+ {
+ sm[i] = R[i];
+ }
+
+ int smOff = SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;
+
+ System.arraycopy(tsk, SPHINCS256Config.SEED_BYTES, masks, 0, Horst.N_MASKS * SPHINCS256Config.HASH_BYTES);
+ for (i = 0; i < (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8; i++)
+ {
+ sm[smOff + i] = (byte)((leafidx >>> 8 * i) & 0xff);
+ }
+
+ smOff += (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;
+
+ Seed.get_seed(hs, seed, 0, tsk, a);
+ Horst ht = new Horst();
+
+ int horst_sigbytes = ht.horst_sign(hs, sm, smOff, root, seed, masks, m_h);
+
+ smOff += horst_sigbytes;
+
+ Wots w = new Wots();
+
+ for (i = 0; i < SPHINCS256Config.N_LEVELS; i++)
+ {
+ a.level = i;
+
+ Seed.get_seed(hs, seed, 0, tsk, a); //XXX: Don't use the same address as for horst_sign here!
+
+ w.wots_sign(hs, sm, smOff, root, seed, masks);
+
+ smOff += Wots.WOTS_SIGBYTES;
+
+ compute_authpath_wots(hs, root, sm, smOff, a, tsk, masks, SPHINCS256Config.SUBTREE_HEIGHT);
+ smOff += SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
+
+ a.subleaf = (int)(a.subtree & ((1 << SPHINCS256Config.SUBTREE_HEIGHT) - 1));
+ a.subtree >>>= SPHINCS256Config.SUBTREE_HEIGHT;
+ }
+
+ zerobytes(tsk, 0, SPHINCS256Config.CRYPTO_SECRETKEYBYTES);
+
+ return sm;
+ }
+
+ private void zerobytes(byte[] tsk, int off, int cryptoSecretkeybytes)
+ {
+ for (int i = 0; i != cryptoSecretkeybytes; i++)
+ {
+ tsk[off + i] = 0;
+ }
+ }
+
+ boolean verify(HashFunctions hs, byte[] m, byte[] sm, byte[] pk)
+ {
+ int i;
+ int smlen = sm.length;
+ long leafidx = 0;
+ byte[] wots_pk = new byte[ Wots.WOTS_L * SPHINCS256Config.HASH_BYTES];
+ byte[] pkhash = new byte[ SPHINCS256Config.HASH_BYTES];
+ byte[] root = new byte[ SPHINCS256Config.HASH_BYTES];
+ byte[] sig = new byte[ SPHINCS256Config.CRYPTO_BYTES];
+ int sigp;
+ byte[] tpk = new byte[ SPHINCS256Config.CRYPTO_PUBLICKEYBYTES];
+
+ if (smlen != SPHINCS256Config.CRYPTO_BYTES)
+ {
+ throw new IllegalArgumentException("signature wrong size");
+ }
+
+ byte[] m_h = new byte[ SPHINCS256Config.MSGHASH_BYTES];
+
+ for (i = 0; i < SPHINCS256Config.CRYPTO_PUBLICKEYBYTES; i++)
+ tpk[i] = pk[i];
+
+ // construct message hash
+ {
+ byte[] R = new byte[ SPHINCS256Config.MESSAGE_HASH_SEED_BYTES];
+
+ for (i = 0; i < SPHINCS256Config.MESSAGE_HASH_SEED_BYTES; i++)
+ R[i] = sm[i];
+
+ System.arraycopy(sm, 0, sig, 0, SPHINCS256Config.CRYPTO_BYTES);
+
+ Digest mHash = hs.getMessageHash();
+
+ // input R
+ mHash.update(R, 0, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);
+
+ // input pub key
+ mHash.update(tpk, 0, SPHINCS256Config.CRYPTO_PUBLICKEYBYTES);
+
+ // input message
+ mHash.update(m, 0, m.length);
+
+ mHash.doFinal(m_h, 0);
+ }
+
+ sigp = 0;
+
+ sigp += SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;
+ smlen -= SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;
+
+
+ for (i = 0; i < (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8; i++)
+ {
+ leafidx ^= ((long)(sig[sigp + i] & 0xff) << (8 * i));
+ }
+
+
+ new Horst().horst_verify(hs, root, sig, sigp + (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8,
+ tpk, m_h);
+
+ sigp += (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;
+ smlen -= (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;
+
+ sigp += Horst.HORST_SIGBYTES;
+ smlen -= Horst.HORST_SIGBYTES;
+
+ Wots w = new Wots();
+
+ for (i = 0; i < SPHINCS256Config.N_LEVELS; i++)
+ {
+ w.wots_verify(hs, wots_pk, sig, sigp, root, tpk);
+
+ sigp += Wots.WOTS_SIGBYTES;
+ smlen -= Wots.WOTS_SIGBYTES;
+
+ Tree.l_tree(hs, pkhash, 0, wots_pk, 0, tpk, 0);
+ validate_authpath(hs, root, pkhash, (int)(leafidx & 0x1f), sig, sigp, tpk, SPHINCS256Config.SUBTREE_HEIGHT);
+ leafidx >>= 5;
+
+ sigp += SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
+ smlen -= SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
+ }
+
+ boolean verified = true;
+ for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
+ {
+ if (root[i] != tpk[i + Horst.N_MASKS * SPHINCS256Config.HASH_BYTES])
+ {
+ verified = false;
+ }
+ }
+
+ return verified;
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java
new file mode 100644
index 00000000..f0a5a82c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class SPHINCSPrivateKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final byte[] keyData;
+
+ public SPHINCSPrivateKeyParameters(byte[] keyData)
+ {
+ super(true);
+ this.keyData = Arrays.clone(keyData);
+ }
+
+ public byte[] getKeyData()
+ {
+ return Arrays.clone(keyData);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java
new file mode 100644
index 00000000..62f458f4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.util.Arrays;
+
+public class SPHINCSPublicKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private final byte[] keyData;
+
+ public SPHINCSPublicKeyParameters(byte[] keyData)
+ {
+ super(false);
+ this.keyData = Arrays.clone(keyData);
+ }
+
+ public byte[] getKeyData()
+ {
+ return Arrays.clone(keyData);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Seed.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Seed.java
new file mode 100644
index 00000000..f0fdf2e1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Seed.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.engines.ChaChaEngine;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Pack;
+
+class Seed
+{
+
+ static void get_seed(HashFunctions hs, byte[] seed, int seedOff, byte[] sk, Tree.leafaddr a)
+ {
+ byte[] buffer = new byte[SPHINCS256Config.SEED_BYTES + 8];
+ long t;
+ int i;
+
+ for (i = 0; i < SPHINCS256Config.SEED_BYTES; i++)
+ {
+ buffer[i] = sk[i];
+ }
+
+ //4 bits to encode level
+ t = a.level;
+ //55 bits to encode subtree
+ t |= a.subtree << 4;
+ //5 bits to encode leaf
+ t |= a.subleaf << 59;
+
+ Pack.longToLittleEndian(t, buffer, SPHINCS256Config.SEED_BYTES);
+
+ hs.varlen_hash(seed, seedOff, buffer, buffer.length);
+ }
+
+
+
+ static void prg(byte[] r, int rOff, long rlen, byte[] key, int keyOff)
+ {
+ byte[] nonce = new byte[8];
+
+ StreamCipher cipher = new ChaChaEngine(12);
+
+ cipher.init(true, new ParametersWithIV(new KeyParameter(key, keyOff, 32), nonce));
+
+ cipher.processBytes(r, rOff, (int)rlen, r, rOff);
+
+ //crypto_stream_chacha12(r, rlen, nonce, key);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Tree.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Tree.java
new file mode 100644
index 00000000..2121ce05
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Tree.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+class Tree
+{
+ static class leafaddr
+ {
+ int level;
+ long subtree;
+ long subleaf;
+
+ public leafaddr()
+ {
+
+ }
+
+ public leafaddr(leafaddr leafaddr)
+ {
+ this.level = leafaddr.level;
+ this.subtree = leafaddr.subtree;
+ this.subleaf = leafaddr.subleaf;
+ }
+ }
+
+ static void l_tree(HashFunctions hs, byte[] leaf, int leafOff, byte[] wots_pk, int pkOff, byte[] masks, int masksOff)
+ {
+ int l = Wots.WOTS_L;
+ int i, j = 0;
+ for (i = 0; i < Wots.WOTS_LOG_L; i++)
+ {
+ for (j = 0; j < (l >>> 1); j++)
+ {
+ hs.hash_2n_n_mask(wots_pk, pkOff + j * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + j * 2 * SPHINCS256Config.HASH_BYTES, masks, masksOff + i * 2 * SPHINCS256Config.HASH_BYTES);
+ }
+
+ if ((l & 1) != 0)
+ {
+ System.arraycopy(wots_pk, pkOff + (l - 1) * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + (l >>> 1) * SPHINCS256Config.HASH_BYTES, SPHINCS256Config.HASH_BYTES);
+ l = (l >>> 1) + 1;
+ }
+ else
+ {
+ l = (l >>> 1);
+ }
+ }
+ System.arraycopy(wots_pk, pkOff, leaf, leafOff, SPHINCS256Config.HASH_BYTES);
+ }
+
+ static void treehash(HashFunctions hs, byte[] node, int nodeOff, int height, byte[] sk, leafaddr leaf, byte[] masks, int masksOff)
+ {
+ leafaddr a = new leafaddr(leaf);
+ int lastnode, i;
+ byte[] stack = new byte[(height + 1) * SPHINCS256Config.HASH_BYTES];
+ int[] stacklevels = new int[height + 1];
+ int stackoffset = 0;
+
+ lastnode = (int)(a.subleaf + (1 << height));
+
+ for (; a.subleaf < lastnode; a.subleaf++)
+ {
+ gen_leaf_wots(hs, stack, stackoffset * SPHINCS256Config.HASH_BYTES, masks, masksOff, sk, a);
+ stacklevels[stackoffset] = 0;
+ stackoffset++;
+ while (stackoffset > 1 && stacklevels[stackoffset - 1] == stacklevels[stackoffset - 2])
+ {
+ //MASKS
+ int maskoffset = 2 * (stacklevels[stackoffset - 1] + Wots.WOTS_LOG_L) * SPHINCS256Config.HASH_BYTES;
+
+ hs.hash_2n_n_mask(stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES, stack, (stackoffset - 2) * SPHINCS256Config.HASH_BYTES,
+ masks, masksOff + maskoffset);
+ stacklevels[stackoffset - 2]++;
+ stackoffset--;
+ }
+ }
+ for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
+ {
+ node[nodeOff + i] = stack[i];
+ }
+ }
+
+ static void gen_leaf_wots(HashFunctions hs, byte[] leaf, int leafOff, byte[] masks, int masksOff, byte[] sk, leafaddr a)
+ {
+ byte[] seed = new byte[SPHINCS256Config.SEED_BYTES];
+ byte[] pk = new byte[Wots.WOTS_L * SPHINCS256Config.HASH_BYTES];
+
+ Wots w = new Wots();
+
+ Seed.get_seed(hs, seed, 0, sk, a);
+
+ w.wots_pkgen(hs, pk, 0, seed, 0, masks, masksOff);
+
+ l_tree(hs, leaf, leafOff, pk, 0, masks, masksOff);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Wots.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Wots.java
new file mode 100644
index 00000000..f1bc669d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/sphincs/Wots.java
@@ -0,0 +1,97 @@
+package org.bouncycastle.pqc.crypto.sphincs;
+
+class Wots
+{
+ static final int WOTS_LOGW = 4;
+
+ static final int WOTS_W = (1 << WOTS_LOGW);
+ static final int WOTS_L1 = ((256 + WOTS_LOGW - 1) / WOTS_LOGW);
+ //#define WOTS_L 133 // for WOTS_W == 4
+ //#define WOTS_L 90 // for WOTS_W == 8
+ static final int WOTS_L = 67; // for WOTS_W == 16
+ static final int WOTS_LOG_L = 7; // for WOTS_W == 16
+ static final int WOTS_SIGBYTES = (WOTS_L * SPHINCS256Config.HASH_BYTES);
+
+ static void expand_seed(byte[] outseeds, int outOff, byte[] inseed, int inOff)
+ {
+ clear(outseeds, outOff, WOTS_L * SPHINCS256Config.HASH_BYTES);
+
+ Seed.prg(outseeds, outOff, WOTS_L * SPHINCS256Config.HASH_BYTES, inseed, inOff);
+ }
+
+ private static void clear(byte[] bytes, int offSet, int length)
+ {
+ for (int i = 0; i != length; i++)
+ {
+ bytes[i + offSet] = 0;
+ }
+ }
+
+ static void gen_chain(HashFunctions hs, byte[] out, int outOff, byte[] seed, int seedOff, byte[] masks, int masksOff, int chainlen)
+ {
+ int i, j;
+ for (j = 0; j < SPHINCS256Config.HASH_BYTES; j++)
+ out[j + outOff] = seed[j + seedOff];
+
+ for (i = 0; i < chainlen && i < WOTS_W; i++)
+ hs.hash_n_n_mask(out, outOff, out, outOff, masks, masksOff + (i * SPHINCS256Config.HASH_BYTES));
+ }
+
+
+ void wots_pkgen(HashFunctions hs, byte[] pk, int pkOff, byte[] sk, int skOff, byte[] masks, int masksOff)
+ {
+ int i;
+ expand_seed(pk, pkOff, sk, skOff);
+ for (i = 0; i < WOTS_L; i++)
+ gen_chain(hs, pk, pkOff + i * SPHINCS256Config.HASH_BYTES, pk, pkOff + i * SPHINCS256Config.HASH_BYTES, masks, masksOff, WOTS_W - 1);
+ }
+
+
+ void wots_sign(HashFunctions hs, byte[] sig, int sigOff, byte[] msg, byte[] sk, byte[] masks)
+ {
+ int[] basew = new int[WOTS_L];
+ int i, c = 0;
+
+ for (i = 0; i < WOTS_L1; i += 2)
+ {
+ basew[i] = msg[i / 2] & 0xf;
+ basew[i + 1] = (msg[i / 2] & 0xff) >>> 4;
+ c += WOTS_W - 1 - basew[i];
+ c += WOTS_W - 1 - basew[i + 1];
+ }
+
+ for (; i < WOTS_L; i++)
+ {
+ basew[i] = c & 0xf;
+ c >>>= 4;
+ }
+
+ expand_seed(sig, sigOff, sk, 0);
+
+ for (i = 0; i < WOTS_L; i++)
+ gen_chain(hs, sig, sigOff + i * SPHINCS256Config.HASH_BYTES, sig, sigOff + i * SPHINCS256Config.HASH_BYTES, masks, 0, basew[i]);
+ }
+
+ void wots_verify(HashFunctions hs, byte[] pk, byte[] sig, int sigOff, byte[] msg, byte[] masks)
+ {
+ int[] basew = new int[WOTS_L];
+ int i, c = 0;
+
+ for (i = 0; i < WOTS_L1; i += 2)
+ {
+ basew[i] = msg[i / 2] & 0xf;
+ basew[i + 1] = (msg[i / 2] & 0xff) >>> 4;
+ c += WOTS_W - 1 - basew[i];
+ c += WOTS_W - 1 - basew[i + 1];
+ }
+
+ for (; i < WOTS_L; i++)
+ {
+ basew[i] = c & 0xf;
+ c >>>= 4;
+ }
+
+ for (i = 0; i < WOTS_L; i++)
+ gen_chain(hs, pk, i * SPHINCS256Config.HASH_BYTES, sig, sigOff + i * SPHINCS256Config.HASH_BYTES, masks, (basew[i] * SPHINCS256Config.HASH_BYTES), WOTS_W - 1 - basew[i]);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/AllTests.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/AllTests.java
index ed73ddf9..e99242d0 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/AllTests.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/AllTests.java
@@ -26,6 +26,7 @@ public class AllTests
suite.addTestSuite(NTRUSignatureKeyTest.class);
suite.addTestSuite(NTRUSignerTest.class);
suite.addTestSuite(NTRUSigningParametersTest.class);
+ suite.addTestSuite(AllTests.SimpleTestTest.class);
return new BCTestSetup(suite);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java
index 69b28428..8b0cad3f 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java
@@ -26,7 +26,8 @@ public class GMSSSignerTest
{
byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
- SecureRandom keyRandom = new FixedSecureRandom(new byte[][]{keyData, keyData});
+ SecureRandom keyRandom = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData) });
public String getName()
{
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePKCSCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java
index edb1d607..266463bc 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePKCSCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java
@@ -5,16 +5,16 @@ import java.util.Random;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCipher;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McEliecePKCSCipher;
-import org.bouncycastle.pqc.crypto.mceliece.McEliecePKCSDigestCipher;
import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters;
import org.bouncycastle.util.test.SimpleTest;
-public class McEliecePKCSCipherTest
+public class McElieceCipherTest
extends SimpleTest
{
@@ -28,6 +28,7 @@ public class McEliecePKCSCipherTest
public void performTest()
+ throws InvalidCipherTextException
{
int numPassesKPG = 1;
int numPassesEncDec = 10;
@@ -45,7 +46,7 @@ public class McEliecePKCSCipherTest
ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
Digest msgDigest = new SHA256Digest();
- McEliecePKCSDigestCipher mcEliecePKCSDigestCipher = new McEliecePKCSDigestCipher(new McEliecePKCSCipher(), msgDigest);
+ McElieceCipher mcEliecePKCSDigestCipher = new McElieceCipher();
for (int k = 1; k <= numPassesEncDec; k++)
@@ -60,18 +61,17 @@ public class McEliecePKCSCipherTest
rand.nextBytes(mBytes);
// encrypt
- mcEliecePKCSDigestCipher.update(mBytes, 0, mBytes.length);
- byte[] enc = mcEliecePKCSDigestCipher.messageEncrypt();
+ msgDigest.update(mBytes, 0, mBytes.length);
+ byte[] hash = new byte[msgDigest.getDigestSize()];
+
+ msgDigest.doFinal(hash, 0);
+
+ byte[] enc = mcEliecePKCSDigestCipher.messageEncrypt(hash);
// initialize for decryption
mcEliecePKCSDigestCipher.init(false, pair.getPrivate());
byte[] constructedmessage = mcEliecePKCSDigestCipher.messageDecrypt(enc);
- // XXX write in McElieceFujisakiDigestCipher?
- msgDigest.update(mBytes, 0, mBytes.length);
- byte[] hash = new byte[msgDigest.getDigestSize()];
- msgDigest.doFinal(hash, 0);
-
boolean verified = true;
for (int i = 0; i < hash.length; i++)
{
@@ -96,7 +96,7 @@ public class McEliecePKCSCipherTest
public static void main(
String[] args)
{
- runTest(new McEliecePKCSCipherTest());
+ runTest(new McElieceCipherTest());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java
index dfc44b65..2e9d50dd 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java
@@ -5,13 +5,13 @@ import java.util.Random;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiCipher;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiDigestCipher;
import org.bouncycastle.util.test.SimpleTest;
public class McElieceFujisakiCipherTest
@@ -28,6 +28,7 @@ public class McElieceFujisakiCipherTest
public void performTest()
+ throws InvalidCipherTextException
{
int numPassesKPG = 1;
int numPassesEncDec = 10;
@@ -35,7 +36,6 @@ public class McElieceFujisakiCipherTest
byte[] mBytes;
for (int j = 0; j < numPassesKPG; j++)
{
-
McElieceCCA2Parameters params = new McElieceCCA2Parameters();
McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
@@ -45,7 +45,7 @@ public class McElieceFujisakiCipherTest
ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
Digest msgDigest = new SHA256Digest();
- McElieceFujisakiDigestCipher mcElieceFujisakiDigestCipher = new McElieceFujisakiDigestCipher(new McElieceFujisakiCipher(), msgDigest);
+ McElieceFujisakiCipher mcElieceFujisakiDigestCipher = new McElieceFujisakiCipher();
for (int k = 1; k <= numPassesEncDec; k++)
@@ -59,18 +59,19 @@ public class McElieceFujisakiCipherTest
mBytes = new byte[mLength];
rand.nextBytes(mBytes);
+ msgDigest.update(mBytes, 0, mBytes.length);
+ byte[] hash = new byte[msgDigest.getDigestSize()];
+ msgDigest.doFinal(hash, 0);
+
// encrypt
- mcElieceFujisakiDigestCipher.update(mBytes, 0, mBytes.length);
- byte[] enc = mcElieceFujisakiDigestCipher.messageEncrypt();
+ byte[] enc = mcElieceFujisakiDigestCipher.messageEncrypt(hash);
// initialize for decryption
mcElieceFujisakiDigestCipher.init(false, pair.getPrivate());
byte[] constructedmessage = mcElieceFujisakiDigestCipher.messageDecrypt(enc);
// XXX write in McElieceFujisakiDigestCipher?
- msgDigest.update(mBytes, 0, mBytes.length);
- byte[] hash = new byte[msgDigest.getDigestSize()];
- msgDigest.doFinal(hash, 0);
+
boolean verified = true;
for (int i = 0; i < hash.length; i++)
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java
index 5845cf61..665e3786 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java
@@ -11,7 +11,6 @@ import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiDigestCipher;
import org.bouncycastle.util.test.SimpleTest;
public class McElieceKobaraImaiCipherTest
@@ -28,6 +27,7 @@ public class McElieceKobaraImaiCipherTest
public void performTest()
+ throws Exception
{
int numPassesKPG = 0; // TODO: this algorithm is broken
int numPassesEncDec = 10;
@@ -36,7 +36,7 @@ public class McElieceKobaraImaiCipherTest
for (int j = 0; j < numPassesKPG; j++)
{
- McElieceCCA2Parameters params = new McElieceCCA2Parameters();
+ McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256");
McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
@@ -45,7 +45,7 @@ public class McElieceKobaraImaiCipherTest
ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
Digest msgDigest = new SHA256Digest();
- McElieceKobaraImaiDigestCipher mcElieceKobaraImaiDigestCipher = new McElieceKobaraImaiDigestCipher(new McElieceKobaraImaiCipher(), msgDigest);
+ McElieceKobaraImaiCipher mcElieceKobaraImaiDigestCipher = new McElieceKobaraImaiCipher();
for (int k = 1; k <= numPassesEncDec; k++)
@@ -59,18 +59,18 @@ public class McElieceKobaraImaiCipherTest
mBytes = new byte[mLength];
rand.nextBytes(mBytes);
+ msgDigest.update(mBytes, 0, mBytes.length);
+ byte[] hash = new byte[msgDigest.getDigestSize()];
+ msgDigest.doFinal(hash, 0);
+
// encrypt
- mcElieceKobaraImaiDigestCipher.update(mBytes, 0, mBytes.length);
- byte[] enc = mcElieceKobaraImaiDigestCipher.messageEncrypt();
+ byte[] enc = mcElieceKobaraImaiDigestCipher.messageEncrypt(hash);
// initialize for decryption
mcElieceKobaraImaiDigestCipher.init(false, pair.getPrivate());
byte[] constructedmessage = mcElieceKobaraImaiDigestCipher.messageDecrypt(enc);
// XXX write in McElieceFujisakiDigestCipher?
- msgDigest.update(mBytes, 0, mBytes.length);
- byte[] hash = new byte[msgDigest.getDigestSize()];
- msgDigest.doFinal(hash, 0);
boolean verified = true;
for (int i = 0; i < hash.length; i++)
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java
index 23ba3f9d..862c4925 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java
@@ -11,7 +11,6 @@ import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalCipher;
-import org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalDigestCipher;
import org.bouncycastle.util.test.SimpleTest;
public class McEliecePointchevalCipherTest
@@ -28,6 +27,7 @@ public class McEliecePointchevalCipherTest
public void performTest()
+ throws Exception
{
int numPassesKPG = 1;
int numPassesEncDec = 10;
@@ -36,7 +36,7 @@ public class McEliecePointchevalCipherTest
for (int j = 0; j < numPassesKPG; j++)
{
- McElieceCCA2Parameters params = new McElieceCCA2Parameters();
+ McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256");
McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
@@ -45,7 +45,7 @@ public class McEliecePointchevalCipherTest
ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
Digest msgDigest = new SHA256Digest();
- McEliecePointchevalDigestCipher mcEliecePointchevalDigestCipher = new McEliecePointchevalDigestCipher(new McEliecePointchevalCipher(), msgDigest);
+ McEliecePointchevalCipher mcEliecePointchevalDigestCipher = new McEliecePointchevalCipher();
for (int k = 1; k <= numPassesEncDec; k++)
@@ -59,18 +59,18 @@ public class McEliecePointchevalCipherTest
mBytes = new byte[mLength];
rand.nextBytes(mBytes);
+ msgDigest.update(mBytes, 0, mBytes.length);
+ byte[] hash = new byte[msgDigest.getDigestSize()];
+ msgDigest.doFinal(hash, 0);
+
// encrypt
- mcEliecePointchevalDigestCipher.update(mBytes, 0, mBytes.length);
- byte[] enc = mcEliecePointchevalDigestCipher.messageEncrypt();
+ byte[] enc = mcEliecePointchevalDigestCipher.messageEncrypt(hash);
// initialize for decryption
mcEliecePointchevalDigestCipher.init(false, pair.getPrivate());
byte[] constructedmessage = mcEliecePointchevalDigestCipher.messageDecrypt(enc);
// XXX write in McElieceFujisakiDigestCipher?
- msgDigest.update(mBytes, 0, mBytes.length);
- byte[] hash = new byte[msgDigest.getDigestSize()];
- msgDigest.doFinal(hash, 0);
boolean verified = true;
for (int i = 0; i < hash.length; i++)
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
new file mode 100644
index 00000000..e0d63ad8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
@@ -0,0 +1,161 @@
+package org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.ExchangePair;
+import org.bouncycastle.pqc.crypto.newhope.NHAgreement;
+import org.bouncycastle.pqc.crypto.newhope.NHExchangePairGenerator;
+import org.bouncycastle.pqc.crypto.newhope.NHKeyPairGenerator;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class NewHopeTest
+ extends SimpleTest
+{
+// private static final byte[] SECRETA = Hex.decode(
+// "0823190c27cf2066195d13721d702f1e2248309e124927d5182f175e348a1e800791357825800808223e236e22c41d4e081a2499139e238814590f3d296e34d7"
+// + "1eaa25fb37aa2dac36fa0bba1b0b113616df29a620150bdb12071636186c27ae1546264f33182e4e11330d8e3024138d2dff18de0f411d930f2f11840a6d1e3c"
+// + "0b0b18a81a8014eb364514f00c3a1ab41295314233e2167b049c3481103f243910ac1eaf16da23322b83227738f02b4d26782f8d0e542e04087319981c760ba8"
+// + "329c303f1b0223b429050ef8121220772cc91355309a36051da5282318fe34c60e7034872b10188e2bc1338e0e890a6a13e508cb12dc261d34bb15950fe82f32"
+// + "1cc8090413ec2c1127b1369b28cd0ada154d307a0e582b85240e24e525af20371d6d0c7e0dcb08b60cc023f10afe166323230f3a0a87279f0cd70e8d29b22c95"
+// + "160d13be312131b032103349346e324f1ff812001770269e31c0251a0ab4221a1cdd2d93215b226d19a12cb407cc287c11d821a00a8022182d1725cb13a50d79"
+// + "303d1d680d111367188932891d771f552fb014d62d0214d534b023a70da30c753212167608ae1ac72e4d26c917491bb1204f23b734eb20171a1e26ae22ae2715"
+// + "116933b60cce1d3717701d051d980b9512ca0eb1189e188f0e2c2cd30c800c6024b310d732d6124723c207b5184818e4308f1c1e22921dee32a91f4a0b8b2e28"
+// + "2c290685063f192628701d701d68196f284a2664234d1aa42af7120d1b2532b3168930aa26a51acf2a8214a50c6b330e059315e205c6297f2fc10d420f8d0680"
+// + "28652c0b1119307f09a30b881d5709d52b6e2a2e1eeb19260f521c77066c18ce27262f0b048428ab1eb20ee71e9c066408b909a5275a09da2ebe254b176518ba"
+// + "12e723df13ef152d1d112d700e1622681fa1310a2000138b09f8315622612e492df60d222a430bac2abd06e125a91e1907c92c3a19f829312a6f2dad0aca1772"
+// + "03f1142b0b2f0bfd17a009c60eb913fe32c908590e8f300521dd31880f2b12a8215f1dfa1d8f168228730fc11ae80ca015da0bd412271c8827512325311b1b83"
+// + "1ef2227723b605af2d7015bd14bf17b712aa304c30821a181bff1f7b22d6323b067a232526720fd91ed8054730e714ad163220a11986213a1c2d1af22958207c"
+// + "2d3428922d710d33207a23831f430a792658042719762dd50b811f412cb20486315219ed084c1b221570327226b60e1907b224b215911ab3266128cf21c623f4"
+// + "08930e9230331dba23790b5c0fdb26530d97323712cd279612d40c7a14341fc323a32893131c2cf520412ca60c28059a09c8181b2303275e2c13119c22772d28"
+// + "1f5304941900134f07d2085b1dd9107b03ab0ce118d206be2eb32d3c0d981bcb0b1920f80b6c0e7b311118cc16542bb61f1005dc0fa9319b25d1165f234d0fdc"
+// + "08e41cc4035605ad04990a0a14142e81172228b31963098a20ac27b723e9161922432b4330ef102d1067316f239e107f071d11e4053b182817f715b72c3a1ab4"
+// + "1b0213a419c618060d9e0ba01be010820ed41e8e28580cd12bd81f7a1f4505be21862ac1262601b814ad10241476048d211c2d541834319909dd0ed11c4c29b8"
+// + "1ba22af20689271821210b22049c0e391f6e0a6406ae1a2d06f322f80db72973127719e70fbb17070f460f732999089523ae28dd1347263431831a932264294a"
+// + "0dc005b6211116c42daf232623ef12fa08040bc8183e1bec1d0510bd2c5f11aa20d60e5405672d46244b2b5b2c5e18740e37304c13b311ac2fb5266129600af1"
+// + "0edc0ccb1b5030bc1abf0c1913b425c0144711a922040f352d5a2c3610390db626142ea614430503062a252f030a20a22ec4308d14fd17be19b12bac06752f86"
+// + "237330d7132006e5229106e52a3b1d64081503c40fd230cd19ae0be3243b2c0b02601e0809421bff0ed72ede16b5201a0a9f27871c4832e023d82a40056f0584"
+// + "136204270dbf1b0103a627c00e9315ce02b004ac1e0e06e025b526cd0e60252231d706c01d5c32fb26fc31452d3a282b20a02c042eb721d10c1126d105702c27"
+// + "21ed246f18482f0e1cf802632ec20da91a501217277516850e0321ab0a3f06d80bb3241d0fee170b247d1be804700cdb28831720108f2e9924312f9a232f197f"
+// + "2aad15b91534092413621c6630f623280b36208014c92fe41d9306982d0d19141b0e053e09f915001fce27b90b521bf00502151114641c50066508f12a290bb4"
+// + "2cb908c22ef225262ddc121a0b3c2a9829f40b8719e616520b1b1c250a94160b19690a552bc22e452086266b315e14bc1240038c31f0098005d22e4e073711ef"
+// + "040d2df103f42555198d30d80eed31c71852035817a80788070c201f286017bc0f082a8b23412f9328f1166f147529e62c2f210e16be1ade0e821346103322f6"
+// + "222d1178119d299a1fd6272415b80d390fd4131a0e6712dd197305a40fd43157302725b315961b952b0513ff0278266c3015077120542d991b7808882b750f3a"
+// + "093906f61288181d269f10aa22782eb5280410d82dc132170e8d1ef71cb5068219491c7514db31420f7e2df627372e5713a8073d2817025d2b862b3004ac2f8f"
+// + "22e11c8f03cc259520d427fb100218a522121be202a22e0f29080f1b23e524941efa21a80d350f76317811d01c7d101b24e10c9e0bed1bbc21e821e31eb7044e"
+// + "2c80287609b123071daa0b93051b2dd205b515a325d92643087814fe1978286a02c03110301b31d121b6261002e91ecb275f090a2afb230612302fbf12f21d2a"
+// + "23771846087324ed14930694317703ac278a249e19af11350e3f05882a5d2b3f26d229f628da06cf06732f7317cc230c2bda037609f5186e2a2e29882b3d1757");
+//
+// private static final byte[] SENDB = Hex.decode(
+// "8c06d4972b4521374d5ce3404823db20bd5b6288795faa324216a54e8cdcd20676ba83609f5db66a1967a6079f9126e512061cf9d58dea45e7814e22c9bc2ff3"
+// + "661546a65985f70da5fb10d675352211e847387c1b5dc0badd34284a552d7904680528d0dbb74e69ab90d844b149d81613a09c46fa6690b845707a6970953755"
+// + "10b2abfc4675a85e3b48908011e4b53bdce691ae64c7c48f35b8c7e02cd68a0eb745139ee560984d015d4d94252408a715f0e58306ad84532794a57a75859499"
+// + "14c4ad68b74189f0ac4d7c8947299a12d981cc2ff3581636b1515cd7b73d103def24321a05a489b8849bb3fa64b5ab690e2a57d4359621d56be79c1f396ed3e2"
+// + "63068c138e64a26be6851dd971a69fe07adea867f1323655ed934ce6ae103464cc2ba96ff038996b0bc9321e1fec6a9844c5389eb6897aa98755aebacbbf9379"
+// + "258b8311a4c44e7287edc6bd8765840eccc7c8b322e57131908ab33985b79b9c1c91077c8d41dedcbad2505459293dba42d0bf56d8f298ad216f7ad26fa817f6"
+// + "4f2e525604d4092f36014e0698660c804b28e1e03e98d391636516e11b7d8d4eb82b60bec3a3bbd4944068574159517028a5d06e721a187e0a9f294569964e96"
+// + "9a56cd371ea8556ea76151a75a4bce622d885f9892c92537ab63c17d43a79704988443980c2cd35ac69c916457e3b230087bcc92c34c607b7a633ae32c39bbbd"
+// + "ad4bf0f98a957e854078061991256da5cbc0d07d0a8a610b1be0063cc8271716866174c28810ad4d40d7d916bafb7a1c8253826569dd2e16d4c5f48baea82fd5"
+// + "d3412f9c680eaf0de8001c8c8766eb87fb81a771c67a269b155ee6a2e158719d205b0a8b7b89480e5c8ef7da18b8437f618c402ef11c5e8a6d59110962c94a4b"
+// + "83a4587b58152ba895deab6c52beb9572474de1cbda147b189cbd4f1c400f985505dcf8497f65408ade1677ab434ecdc19aad3ba558e83aa5200b5555e812d2b"
+// + "3320812b9e4fb47b20948c40269a115118b941be5926ad77c09b89a72f56be50c716e4016d384dda5fd0ab014847dccdd3044a94a8537e2b8e20043cc19be364"
+// + "128632016321456ab2f390e29a43e42155656d5b5fb96a9812f71323b88899279f9b4da45fc26a6c91f7dd868e4aa12abef11b21e59e6758fd9c8118fb4aaeed"
+// + "6700a8bcdad2228f9dd15593a3b1207d24f2a0d40034de9265f609acaa17e93cca96899f67811ffa9265786217d340f42a09316766d3fc8829a71d8ce7213433"
+// + "c6c515fbd8b9626bc1b67a0f6946de4b886792aa2f77030d08532eadfea21e80d902b9d24472e363a26a6dd8cee685b88517438949373e4a11a18002240e0341"
+// + "2c6057a230b7b51354891a86407ec612f8fdf538d08fd925812815c2d4a78ab2268e0f283e76dced3a410f396501643dbc494c55c9fd5c5ed08e28472100df58"
+// + "2da681fc71fa200e83d3a860d556c456614c93f5c69e013d6c53ee6fe9423b9d277d4da32b6681af7d9e890b8fb01700d679881e017edd142d32f3e5bee54050"
+// + "3372519abcc796b2d830042b0f7b97e639188b21c7231552053ed508b5ed851c0681d850230879a7c46f185a5a54b7dc1933c782434158fc43480d80d65714ab"
+// + "54452d5544987187c655a2a3f41bbe187988c1a0702ad03a8c530262141c75830a6e962bda4f208f7a7a6f4ead5995b985bd3c5a5029aa92f6f56405c2d08155"
+// + "6d860441e077e0053ae74061f9351e7927871b75625d0cb2433e205bb97030c5ccc9fffe9cedc62a683db90e396f2eb485305d62a76c782cbe66508bf5b130b2"
+// + "8c8da2c993865d667e22e789301a1a94506d995d6a11581f4f314e7cbfcc4c65e7d76e48062ecff6fa32af5ac58b00b738421b211ad9ad060a3b2b67903ad28e"
+// + "4b2214c3a14429a0d68369f856132b24e183c48991c28c35e6be2e83c1ccf078199189f55d835798008270cdbe409a5c9954c63e400e6d91694850e2352e8559"
+// + "c34f19f7fd4c429bcb0bba944d8c0c41706361b967c96ba1eaa266cea84cd37f0c6a40caafaae8d40a89d0ca06967ca910d6a20a29685dfc2be692b0f9b0ec96"
+// + "9723bc5996926bb2d806d86369a04dd7c272752467922128b2966b868b4559fe936baaf5c8b6892c916dab935381387da2e0f71cb26abf089913820a33b564a5"
+// + "2b625d810c570cd147d212e649f994a1a2a7ac2e30e310f1be5359cb892016123cd27dd4efd64227eb83a90e99a79fcbc9176be25c838eb6eabbee8bbb455259"
+// + "269197ac4c66ea383e5e265aeb1bf64c34ffd4779a6800ac4e12b1277a8c59b89f4c728cc93e71ec93c7bfd09a8e9cbf19bde439aa95a2a35c31ab4b4314d252"
+// + "b5702f1ed69573fe12315f3561efc22ddb4b98a747922b4944c79457e430e9adbe98dcc0231bdc88a58bf67c034da18584dc7c49c776892236b67c1762f3eb1d"
+// + "7f2323aebbf211b2b8074d29273847e50f8d43bcae33db20678a3ed61f7ac49ea6a3f0361cd0c1752c7a0a78ad52d8c9ae755b575dd28bf05b7b0ef438b85d89"
+// + "f9edd1f598c8e972211d971df25d64d9a29fecb4de3c828219434ade29509f6170142ac0756b7176658fa4f3f7e00f2cac901db5e0bc6c3d5c0028572ff0de3a"
+// + "f09cf1935e7c3231ad025570a895e9edbbe8d509df51a7297e729cf24e83c1e5237536417c96bc265addcf7b9f6e4dccfe45a4219b533d5db3c596cc2eed06ae"
+// + "de6f4a9d6935367e204127eeb4547c38d830e7e9e99cac5effef27b8f57dd07c2e60e4d79ab22e250829d347c5a80730ed957a83334b1a1470d08db01b9552dc"
+// + "092b1d3597c97f34332d4e1e503a3b755ade39b68a5ef9b9c13efd7cc4f47484dab6000750222510cfee516c5f23efdf70fd196fcf136a0bdb23745707a95a4a");
+//
+// private static final byte[] KEYB = Hex.decode("5946400eed4b18ce8d7fb1f744e46e5689009aa4672526c0c59a0adb3dd3ca37");
+
+ private static final int ROUNDS = 1000;
+
+ private void testKeyExchange() throws Exception
+ {
+ SecureRandom aliceRand = new SecureRandom();
+ SecureRandom bobRand = new SecureRandom();
+
+ for (int i = 0; i < ROUNDS; ++i)
+ {
+ NHKeyPairGenerator kpGen = new NHKeyPairGenerator();
+
+ kpGen.init(new KeyGenerationParameters(aliceRand, 2048));
+
+ AsymmetricCipherKeyPair aliceKp = kpGen.generateKeyPair();
+
+ NHExchangePairGenerator exchGen = new NHExchangePairGenerator(bobRand);
+
+ ExchangePair bobExchPair = exchGen.GenerateExchange(aliceKp.getPublic());
+
+ NHAgreement agreement = new NHAgreement();
+
+ agreement.init(aliceKp.getPrivate());
+
+ byte[] aliceSharedKey = agreement.calculateAgreement(bobExchPair.getPublicKey());
+
+ isTrue("value mismatch", Arrays.areEqual(aliceSharedKey, bobExchPair.getSharedValue()));
+ }
+ }
+
+ private void testInterop()
+ {
+ /*
+ * Test interoperability with the C reference implementation as of:
+ *
+ * https://github.com/tpoeppelmann/newhope/commit/bc06c1ac04101449797ae8d1029e73cdcd82f79f
+ *
+ * (version corresponding to the newhope-20160328.pdf paper).
+ *
+ * Note that 'SENDB' and 'KEYB' were both generated by the C implementation upon receipt of a
+ * 'SENDA' (not kept) generated together with 'SECRETA'.
+ */
+
+ // NOTE: This passes as of writing, but requires public access to NewHope (currently package scope)
+ /*
+ short[] secretA = new short[SECRETA.length / 2];
+ for (int i = 0; i < secretA.length; ++i)
+ {
+ secretA[i] = Pack.bigEndianToShort(SECRETA, 2 * i);
+ }
+
+ byte[] keyA = new byte[NewHope.AGREEMENT_SIZE];
+ NewHope.sharedA(keyA, secretA, SENDB);
+
+ isTrue("value mismatch", Arrays.areEqual(keyA, KEYB));
+ */
+ }
+
+ public String getName()
+ {
+ return "NewHope";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testKeyExchange();
+ testInterop();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new NewHopeTest());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java
index ae6774b6..0c573d85 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java
@@ -23,8 +23,8 @@ extends SimpleTest
{
byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
- SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData });
-
+ SecureRandom keyRandom = new FixedSecureRandom(
+ new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData) });
public String getName()
{
@@ -53,7 +53,7 @@ extends SimpleTest
rainbowSigner.init(false, pair.getPublic());
rainbowSigner.update(message, 0, message.length);
- if (!rainbowSigner.verify(sig))
+ if (!rainbowSigner.verifySignature(sig))
{
fail("verification fails");
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RegressionTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RegressionTest.java
index bc5a9794..2e51e7ba 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RegressionTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/RegressionTest.java
@@ -9,9 +9,11 @@ public class RegressionTest
new GMSSSignerTest(),
new McElieceFujisakiCipherTest(),
new McElieceKobaraImaiCipherTest(),
- new McEliecePKCSCipherTest(),
+ new McElieceCipherTest(),
new McEliecePointchevalCipherTest(),
- new RainbowSignerTest()
+ new RainbowSignerTest() ,
+ new Sphincs256Test(),
+ new NewHopeTest()
};
public static void main(
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java
new file mode 100644
index 00000000..88b5c6a5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java
@@ -0,0 +1,1679 @@
+package org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHA512tDigest;
+import org.bouncycastle.pqc.crypto.MessageSigner;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyPairGenerator;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256Signer;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.test.SimpleTest;
+
+
+public class Sphincs256Test
+ extends SimpleTest
+{
+ // test vector courtesy the "Yawning Angel" GO implementation and the SUPERCOP reference implementation.
+ byte[] msg = Strings.toByteArray("Cthulhu Fthagn --What a wonderful phrase!Cthulhu Fthagn --Say it and you're crazed!");
+
+ byte[] expBlakePub = Base64.decode(
+ "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktM"
+ + "TU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+ + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm"
+ + "p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+ + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8A"
+ + "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+ + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla"
+ + "W1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+ + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0"
+ + "tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+ + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0O"
+ + "DxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+ + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdo"
+ + "aWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+ + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHC"
+ + "w8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+ + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhsc"
+ + "HR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+ + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2"
+ + "d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+ + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q"
+ + "0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+ + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHweosZZTNIli4FJn"
+ + "DJwDmiT955i6r8DOENuXZL6Be24i");
+
+ byte[] expBlakePriv = Base64.decode(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss"
+ + "LS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+ + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG"
+ + "h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+ + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g"
+ + "4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+ + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6"
+ + "Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+ + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOU"
+ + "lZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+ + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u"
+ + "7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+ + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdI"
+ + "SUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+ + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGi"
+ + "o6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+ + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8"
+ + "/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+ + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW"
+ + "V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+ + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+w"
+ + "sbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+ + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkK"
+ + "CwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+ + "ODk6Ozw9Pj8=");
+
+ byte[] expBlakeSig = Base64.decode(
+ "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");
+
+ byte[] expSha2Pub = Base64.decode(
+ "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+ + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+ + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+ + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+ + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+ + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+ + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+ + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+ + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+ + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+ + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+ + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH6oCyxVnw+pTAdU/b4PWLQU4M29Fe8TFHP+s9whN/N+Y");
+
+ byte[] expSha2Priv = Base64.decode(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+ + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+ + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+ + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+ + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+ + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+ + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+ + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+ + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+ + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+ + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+ + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+ + "ODk6Ozw9Pj8=");
+
+ byte[] expSha2Sig = Base64.decode(
+ "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");
+
+ byte[] expSha3Pub = Base64.decode(
+ "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+ + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+ + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+ + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+ + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+ + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+ + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+ + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+ + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+ + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+ + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+ + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHzzFqLKvvsdZOxldDTvCy40RGXZFsOAMP1jw0XlUMqq9");
+
+ byte[] expSha3Priv = Base64.decode(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+ + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+ + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+ + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+ + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+ + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+ + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+ + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+ + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+ + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+ + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+ + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+ + "ODk6Ozw9Pj8=");
+
+ byte[] expSha3Sig = Base64.decode(
+ "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");
+
+ public String getName()
+ {
+ return "Sphincs256";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ // doBlakeKatTest(); TODO: digest classes still need some work...
+ doSHA2KatTest();
+ doSHA2RandomTest();
+ doSHA3KatTest();
+ doSHA3RandomTest();
+ }
+ /*
+ private void doBlakeKatTest()
+ {
+ Sphincs256KeyPairGenerator generator = new Sphincs256KeyPairGenerator();
+
+ generator.init(new Sphincs256KeyGenerationParameters(new RiggedRandom(), new Blake256Digest()));
+
+ AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+ SphincsPrivateKeyParameters priv = (SphincsPrivateKeyParameters)kp.getPrivate();
+
+ SphincsPublicKeyParameters pub = (SphincsPublicKeyParameters)kp.getPublic();
+
+ isTrue("blake pub mismatch", areEqual(expBlakePub, pub.getKeyData()));
+ isTrue("blake priv mismatch", areEqual(expBlakePriv, priv.getKeyData()));
+
+ MessageSigner sphincsSigner = new Sphincs256Signer(new Blake256Digest(), new Blake512Digest());
+
+ sphincsSigner.init(true, priv);
+
+ byte[] sig = sphincsSigner.generateSignature(msg);
+
+ isTrue("blake sig mismatch", areEqual(expBlakeSig, sig));
+
+ sphincsSigner.init(false, pub);
+
+ isTrue("blake sig verify failed", sphincsSigner.verifySignature(msg, sig));
+ isTrue("blake wrong verify failed", !sphincsSigner.verifySignature(msg, expSha2Sig));
+ }
+ */
+
+ private void doSHA2KatTest()
+ {
+ SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+ generator.init(new SPHINCS256KeyGenerationParameters(new RiggedRandom(), new SHA512tDigest(256)));
+
+ AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+ SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+ SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+ isTrue("sha2 pub mismatch", areEqual(expSha2Pub, pub.getKeyData()));
+ isTrue("sha2 priv mismatch", areEqual(expSha2Priv, priv.getKeyData()));
+
+ MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest());
+
+ sphincsSigner.init(true, priv);
+
+ byte[] sig = sphincsSigner.generateSignature(msg);
+
+ isTrue("sha2 sig mismatch", areEqual(expSha2Sig, sig));
+
+ sphincsSigner.init(false, pub);
+
+ isTrue("sha2 sig verify failed", sphincsSigner.verifySignature(msg, sig));
+ isTrue("sha2 wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+ }
+
+ private void doSHA3KatTest()
+ {
+ SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+ generator.init(new SPHINCS256KeyGenerationParameters(new RiggedRandom(), new SHA3Digest(256)));
+
+ AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+ SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+ SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+ isTrue("sha3 pub mismatch", areEqual(expSha3Pub, pub.getKeyData()));
+ isTrue("sha3 priv mismatch", areEqual(expSha3Priv, priv.getKeyData()));
+
+ MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512));
+
+ sphincsSigner.init(true, priv);
+
+ byte[] sig = sphincsSigner.generateSignature(msg);
+
+ isTrue("sha3 sig mismatch", areEqual(expSha3Sig, sig));
+
+ sphincsSigner.init(false, pub);
+
+ isTrue("sha3 sig verify failed", sphincsSigner.verifySignature(msg, sig));
+ isTrue("sha3 wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+ }
+
+ private void doSHA2RandomTest()
+ {
+ SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+ generator.init(new SPHINCS256KeyGenerationParameters(new SecureRandom(), new SHA512tDigest(256)));
+
+ AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+ SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+ SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+ MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest());
+
+ sphincsSigner.init(true, priv);
+
+ byte[] sig = sphincsSigner.generateSignature(msg);
+
+ sphincsSigner.init(false, pub);
+
+ isTrue("sha2 r sig verify failed", sphincsSigner.verifySignature(msg, sig));
+ isTrue("sha2 r wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+ }
+
+ private void doSHA3RandomTest()
+ {
+ SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+ generator.init(new SPHINCS256KeyGenerationParameters(new SecureRandom(), new SHA3Digest(256)));
+
+ AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+ SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+ SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+ MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512));
+
+ sphincsSigner.init(true, priv);
+
+ byte[] sig = sphincsSigner.generateSignature(msg);
+
+ sphincsSigner.init(false, pub);
+
+ isTrue("sha3 r sig verify failed", sphincsSigner.verifySignature(msg, sig));
+ isTrue("sha3 r wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+ }
+
+ private static class RiggedRandom
+ extends SecureRandom
+ {
+ public void nextBytes(byte[] bytes)
+ {
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(i & 0xff);
+ }
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new Sphincs256Test());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHKey.java
new file mode 100644
index 00000000..ccf8a1b3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHKey.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.pqc.jcajce.interfaces;
+
+import java.security.Key;
+
+public interface NHKey
+ extends Key
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPrivateKey.java
new file mode 100644
index 00000000..245fb68b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPrivateKey.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.pqc.jcajce.interfaces;
+
+import java.security.PrivateKey;
+
+public interface NHPrivateKey
+ extends NHKey, PrivateKey
+{
+ short[] getSecretData();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPublicKey.java
new file mode 100644
index 00000000..6e16e44f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NHPublicKey.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.pqc.jcajce.interfaces;
+
+import java.security.PublicKey;
+
+public interface NHPublicKey
+ extends NHKey, PublicKey
+{
+ byte[] getPublicData();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SPHINCSKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SPHINCSKey.java
new file mode 100644
index 00000000..73b2ff4f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SPHINCSKey.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.pqc.jcajce.interfaces;
+
+import java.security.Key;
+
+public interface SPHINCSKey
+ extends Key
+{
+ byte[] getKeyData();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
index 4929684a..47d0a4ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
@@ -21,7 +21,7 @@ public class BouncyCastlePQCProvider
extends Provider
implements ConfigurableProvider
{
- private static String info = "BouncyCastle Post-Quantum Security Provider v1.54";
+ private static String info = "BouncyCastle Post-Quantum Security Provider v1.56";
public static String PROVIDER_NAME = "BCPQC";
@@ -36,7 +36,7 @@ public class BouncyCastlePQCProvider
private static final String ALGORITHM_PACKAGE = "org.bouncycastle.pqc.jcajce.provider.";
private static final String[] ALGORITHMS =
{
- "Rainbow", "McEliece"
+ "Rainbow", "McEliece", "SPHINCS", "NH"
};
/**
@@ -46,7 +46,7 @@ public class BouncyCastlePQCProvider
*/
public BouncyCastlePQCProvider()
{
- super(PROVIDER_NAME, 1.54, info);
+ super(PROVIDER_NAME, 1.56, info);
AccessController.doPrivileged(new PrivilegedAction()
{
@@ -137,13 +137,24 @@ public class BouncyCastlePQCProvider
public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
{
- keyInfoConverters.put(oid, keyInfoConverter);
+ synchronized (keyInfoConverters)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+ }
+
+ private static AsymmetricKeyInfoConverter getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm)
+ {
+ synchronized (keyInfoConverters)
+ {
+ return (AsymmetricKeyInfoConverter)keyInfoConverters.get(algorithm);
+ }
}
public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
throws IOException
{
- AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+ AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(publicKeyInfo.getAlgorithm().getAlgorithm());
if (converter == null)
{
@@ -156,7 +167,7 @@ public class BouncyCastlePQCProvider
public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
throws IOException
{
- AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+ AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
if (converter == null)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java
index cb5f648b..c3b69e59 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java
@@ -17,46 +17,25 @@ public class McEliece
public void configure(ConfigurableProvider provider)
{
- // McElieceKobaraImai
- provider.addAlgorithm("KeyPairGenerator.McElieceKobaraImai", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
- // McEliecePointcheval
- provider.addAlgorithm("KeyPairGenerator.McEliecePointcheval", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
- // McElieceFujisaki
- provider.addAlgorithm("KeyPairGenerator.McElieceFujisaki", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
- // McEliecePKCS
- provider.addAlgorithm("KeyPairGenerator.McEliecePKCS", PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
-
- provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcEliece, PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
- provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcElieceCca2, PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
-
+ provider.addAlgorithm("KeyPairGenerator.McElieceKobaraImai", PREFIX + "McElieceCCA2KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyPairGenerator.McEliecePointcheval", PREFIX + "McElieceCCA2KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyPairGenerator.McElieceFujisaki", PREFIX + "McElieceCCA2KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyPairGenerator.McEliece", PREFIX + "McElieceKeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyPairGenerator.McEliece-CCA2", PREFIX + "McElieceCCA2KeyPairGeneratorSpi");
+
+ provider.addAlgorithm("KeyFactory.McElieceKobaraImai", PREFIX + "McElieceCCA2KeyFactorySpi");
+ provider.addAlgorithm("KeyFactory.McEliecePointcheval", PREFIX + "McElieceCCA2KeyFactorySpi");
+ provider.addAlgorithm("KeyFactory.McElieceFujisaki", PREFIX + "McElieceCCA2KeyFactorySpi");
+ provider.addAlgorithm("KeyFactory.McEliece", PREFIX + "McElieceKeyFactorySpi");
+ provider.addAlgorithm("KeyFactory.McEliece-CCA2", PREFIX + "McElieceCCA2KeyFactorySpi");
+
+ provider.addAlgorithm("KeyFactory." + PQCObjectIdentifiers.mcElieceCca2, PREFIX + "McElieceCCA2KeyFactorySpi");
+ provider.addAlgorithm("KeyFactory." + PQCObjectIdentifiers.mcEliece, PREFIX + "McElieceKeyFactorySpi");
+
+ provider.addAlgorithm("Cipher.McEliece", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
provider.addAlgorithm("Cipher.McEliecePointcheval", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
- provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA1", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
- provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA224", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval224");
- provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA256", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval256");
- provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA384", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval384");
- provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA512", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval512");
-
- provider.addAlgorithm("Cipher.McEliecePKCS", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
- provider.addAlgorithm("Cipher.McEliecePKCSWithSHA1", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
- provider.addAlgorithm("Cipher.McEliecePKCSWithSHA224", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS224");
- provider.addAlgorithm("Cipher.McEliecePKCSWithSHA256", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS256");
- provider.addAlgorithm("Cipher.McEliecePKCSWithSHA384", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS384");
- provider.addAlgorithm("Cipher.McEliecePKCSWithSHA512", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS512");
-
provider.addAlgorithm("Cipher.McElieceKobaraImai", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
- provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA1", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
- provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA224", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai224");
- provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA256", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai256");
- provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA384", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai384");
- provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA512", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai512");
-
provider.addAlgorithm("Cipher.McElieceFujisaki", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
- provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA1", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
- provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA224", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki224");
- provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA256", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki256");
- provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA384", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki384");
- provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA512", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki512");
-
}
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NH.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NH.java
new file mode 100644
index 00000000..388e4ea6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NH.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.pqc.jcajce.provider;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi;
+
+public class NH
+{
+ private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".newhope.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.NH", PREFIX + "NHKeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.NH", PREFIX + "NHKeyPairGeneratorSpi");
+
+ provider.addAlgorithm("KeyAgreement.NH", PREFIX + "KeyAgreementSpi");
+
+ AsymmetricKeyInfoConverter keyFact = new NHKeyFactorySpi();
+
+ registerOid(provider, PQCObjectIdentifiers.newHope, "NH", keyFact);
+ registerOidAlgorithmParameters(provider, PQCObjectIdentifiers.newHope, "NH");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/SPHINCS.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/SPHINCS.java
new file mode 100644
index 00000000..06f1ea04
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/SPHINCS.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.pqc.jcajce.provider;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi;
+
+public class SPHINCS
+{
+ private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".sphincs.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.SPHINCS256", PREFIX + "Sphincs256KeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.SPHINCS256", PREFIX + "Sphincs256KeyPairGeneratorSpi");
+
+ addSignatureAlgorithm(provider, "SHA512", "SPHINCS256", PREFIX + "SignatureSpi$withSha512", PQCObjectIdentifiers.sphincs256_with_SHA512);
+ addSignatureAlgorithm(provider, "SHA3-512", "SPHINCS256", PREFIX + "SignatureSpi$withSha3_512", PQCObjectIdentifiers.sphincs256_with_SHA3_512);
+
+ AsymmetricKeyInfoConverter keyFact = new Sphincs256KeyFactorySpi();
+
+ registerOid(provider, PQCObjectIdentifiers.sphincs256, "SPHINCS256", keyFact);
+ registerOidAlgorithmParameters(provider, PQCObjectIdentifiers.sphincs256, "SPHINCS256");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
index eacefaba..9401c8a0 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
@@ -10,7 +10,6 @@ import org.bouncycastle.pqc.asn1.ParSet;
import org.bouncycastle.pqc.crypto.gmss.GMSSParameters;
import org.bouncycastle.pqc.crypto.gmss.GMSSPublicKeyParameters;
import org.bouncycastle.pqc.jcajce.provider.util.KeyUtil;
-import org.bouncycastle.pqc.jcajce.spec.GMSSPublicKeySpec;
import org.bouncycastle.util.encoders.Hex;
/**
@@ -18,7 +17,6 @@ import org.bouncycastle.util.encoders.Hex;
* href="GMSSKeyPairGenerator">GMSSKeyPairGenerator</a>.
*
* @see org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator
- * @see org.bouncycastle.pqc.jcajce.spec.GMSSPublicKeySpec
*/
public class BCGMSSPublicKey
implements CipherParameters, PublicKey
@@ -55,16 +53,6 @@ public class BCGMSSPublicKey
this.publicKeyBytes = pub;
}
- /**
- * The constructor
- *
- * @param keySpec a GMSS key specification
- */
- protected BCGMSSPublicKey(GMSSPublicKeySpec keySpec)
- {
- this(keySpec.getPublicKey(), keySpec.getParameters());
- }
-
public BCGMSSPublicKey(
GMSSPublicKeyParameters params)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
index 92cdbcac..b04158ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
@@ -3,17 +3,13 @@ package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
import java.security.PrivateKey;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
-import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
@@ -26,94 +22,25 @@ import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
* @see McElieceCCA2KeyPairGenerator
*/
public class BCMcElieceCCA2PrivateKey
- implements CipherParameters, PrivateKey
+ implements PrivateKey
{
-
-
- /**
- *
- */
private static final long serialVersionUID = 1L;
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the dimension of the code, k>=n-mt
- private int k;
-
- // the finte field GF(2^m)
- private GF2mField field;
-
- // the irreducible Goppa polynomial
- private PolynomialGF2mSmallM goppaPoly;
-
- // the permutation
- private Permutation p;
-
- // the canonical check matrix
- private GF2Matrix h;
-
- // the matrix used to compute square roots in (GF(2^m))^t
- private PolynomialGF2mSmallM[] qInv;
-
- private McElieceCCA2Parameters mcElieceCCA2Params;
-
- /**
- * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
- *
- * @param n the length of the code
- * @param k the dimension of the code
- * @param field the field polynomial
- * @param gp the irreducible Goppa polynomial
- * @param p the permutation
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2^m))^t</tt>
- */
- public BCMcElieceCCA2PrivateKey(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
- PolynomialGF2mSmallM[] qInv)
- {
- this.oid = oid;
- this.n = n;
- this.k = k;
- this.field = field;
- this.goppaPoly = gp;
- this.p = p;
- this.h = h;
- this.qInv = qInv;
- }
-
- /**
- * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
- *
- * @param keySpec a {@link McElieceCCA2PrivateKeySpec}
- */
- public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeySpec keySpec)
- {
- this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
- .getGoppaPoly(), keySpec.getP(), keySpec.getH(), keySpec
- .getQInv());
- }
+ private McElieceCCA2PrivateKeyParameters params;
public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeyParameters params)
{
- this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
- params.getP(), params.getH(), params.getQInv());
- this.mcElieceCCA2Params = params.getParameters();
+ this.params = params;
}
/**
* Return the name of the algorithm.
*
- * @return "McEliece"
+ * @return "McEliece-CCA2"
*/
public String getAlgorithm()
{
- return "McEliece";
+ return "McEliece-CCA2";
}
/**
@@ -121,7 +48,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public int getN()
{
- return n;
+ return params.getN();
}
/**
@@ -129,7 +56,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public int getK()
{
- return k;
+ return params.getK();
}
/**
@@ -137,7 +64,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public int getT()
{
- return goppaPoly.getDegree();
+ return params.getGoppaPoly().getDegree();
}
/**
@@ -145,7 +72,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public GF2mField getField()
{
- return field;
+ return params.getField();
}
/**
@@ -153,7 +80,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public PolynomialGF2mSmallM getGoppaPoly()
{
- return goppaPoly;
+ return params.getGoppaPoly();
}
/**
@@ -161,7 +88,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public Permutation getP()
{
- return p;
+ return params.getP();
}
/**
@@ -169,7 +96,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public GF2Matrix getH()
{
- return h;
+ return params.getH();
}
/**
@@ -177,7 +104,7 @@ public class BCMcElieceCCA2PrivateKey
*/
public PolynomialGF2mSmallM[] getQInv()
{
- return qInv;
+ return params.getQInv();
}
/**
@@ -186,9 +113,9 @@ public class BCMcElieceCCA2PrivateKey
public String toString()
{
String result = "";
- result += " extension degree of the field : " + n + "\n";
- result += " dimension of the code : " + k + "\n";
- result += " irreducible Goppa polynomial : " + goppaPoly + "\n";
+ result += " extension degree of the field : " + getN() + "\n";
+ result += " dimension of the code : " + getK() + "\n";
+ result += " irreducible Goppa polynomial : " + getGoppaPoly() + "\n";
return result;
}
@@ -207,10 +134,10 @@ public class BCMcElieceCCA2PrivateKey
BCMcElieceCCA2PrivateKey otherKey = (BCMcElieceCCA2PrivateKey)other;
- return (n == otherKey.n) && (k == otherKey.k)
- && field.equals(otherKey.field)
- && goppaPoly.equals(otherKey.goppaPoly) && p.equals(otherKey.p)
- && h.equals(otherKey.h);
+ return (getN() == otherKey.getN()) && (getK() == otherKey.getK())
+ && getField().equals(otherKey.getField())
+ && getGoppaPoly().equals(otherKey.getGoppaPoly()) && getP().equals(otherKey.getP())
+ && getH().equals(otherKey.getH());
}
/**
@@ -218,37 +145,17 @@ public class BCMcElieceCCA2PrivateKey
*/
public int hashCode()
{
- return k + n + field.hashCode() + goppaPoly.hashCode() + p.hashCode()
- + h.hashCode();
- }
+ int code = params.getK();
- /**
- * @return the OID of the algorithm
- */
- public String getOIDString()
- {
- return oid;
- }
+ code = code * 37 + params.getN();
+ code = code * 37 + params.getField().hashCode();
+ code = code * 37 + params.getGoppaPoly().hashCode();
+ code = code * 37 + params.getP().hashCode();
- /**
- * @return the OID to encode in the SubjectPublicKeyInfo structure
- */
- protected ASN1ObjectIdentifier getOID()
- {
- return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
+ return code * 37 + params.getH().hashCode();
}
/**
- * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
- * structure
- */
- protected ASN1Primitive getAlgParams()
- {
- return null; // FIXME: needed at all?
- }
-
-
- /**
* Return the keyData to encode in the SubjectPublicKeyInfo structure.
* <p>
* The ASN.1 definition of the key structure is
@@ -264,43 +171,34 @@ public class BCMcElieceCCA2PrivateKey
* }
* </pre>
* </p>
+ *
* @return the keyData to encode in the SubjectPublicKeyInfo structure
*/
public byte[] getEncoded()
{
- McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, p, h, qInv);
PrivateKeyInfo pki;
try
{
- AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(getN(), getK(), getField(), getGoppaPoly(), getP(), Utils.getDigAlgId(params.getDigest()));
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2);
+
pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+
+ return pki.getEncoded();
}
catch (IOException e)
{
- e.printStackTrace();
- return null;
- }
- try
- {
- byte[] encoded = pki.getEncoded();
- return encoded;
- }
- catch (IOException e)
- {
- e.printStackTrace();
return null;
}
}
public String getFormat()
{
- // TODO Auto-generated method stub
- return null;
+ return "PKCS#8";
}
- public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ AsymmetricKeyParameter getKeyParams()
{
- return mcElieceCCA2Params;
+ return params;
}
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
index f6064640..79ed7db9 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
@@ -4,17 +4,14 @@ package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
import java.security.PublicKey;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
-import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
/**
@@ -30,49 +27,11 @@ public class BCMcElieceCCA2PublicKey
*/
private static final long serialVersionUID = 1L;
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the error correction capability of the code
- private int t;
-
- // the generator matrix
- private GF2Matrix g;
-
- private McElieceCCA2Parameters McElieceCCA2Params;
-
- /**
- * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
- *
- * @param n the length of the code
- * @param t the error correction capability of the code
- * @param g the generator matrix
- */
- public BCMcElieceCCA2PublicKey(String oid, int n, int t, GF2Matrix g)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.g = g;
- }
-
- /**
- * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
- *
- * @param keySpec a {@link McElieceCCA2PublicKeySpec}
- */
- public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeySpec keySpec)
- {
- this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getMatrixG());
- }
+ private McElieceCCA2PublicKeyParameters params;
public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeyParameters params)
{
- this(params.getOIDString(), params.getN(), params.getT(), params.getMatrixG());
- this.McElieceCCA2Params = params.getParameters();
+ this.params = params;
}
/**
@@ -82,7 +41,7 @@ public class BCMcElieceCCA2PublicKey
*/
public String getAlgorithm()
{
- return "McEliece";
+ return "McEliece-CCA2";
}
/**
@@ -90,7 +49,7 @@ public class BCMcElieceCCA2PublicKey
*/
public int getN()
{
- return n;
+ return params.getN();
}
/**
@@ -98,7 +57,7 @@ public class BCMcElieceCCA2PublicKey
*/
public int getK()
{
- return g.getNumRows();
+ return params.getK();
}
/**
@@ -106,7 +65,7 @@ public class BCMcElieceCCA2PublicKey
*/
public int getT()
{
- return t;
+ return params.getT();
}
/**
@@ -114,7 +73,7 @@ public class BCMcElieceCCA2PublicKey
*/
public GF2Matrix getG()
{
- return g;
+ return params.getG();
}
/**
@@ -123,9 +82,9 @@ public class BCMcElieceCCA2PublicKey
public String toString()
{
String result = "McEliecePublicKey:\n";
- result += " length of the code : " + n + "\n";
- result += " error correction capability: " + t + "\n";
- result += " generator matrix : " + g.toString();
+ result += " length of the code : " + params.getN() + "\n";
+ result += " error correction capability: " + params.getT() + "\n";
+ result += " generator matrix : " + params.getG().toString();
return result;
}
@@ -144,7 +103,7 @@ public class BCMcElieceCCA2PublicKey
BCMcElieceCCA2PublicKey otherKey = (BCMcElieceCCA2PublicKey)other;
- return (n == otherKey.n) && (t == otherKey.t) && (g.equals(otherKey.g));
+ return (params.getN() == otherKey.getN()) && (params.getT() == otherKey.getT()) && (params.getG().equals(otherKey.getG()));
}
/**
@@ -152,32 +111,7 @@ public class BCMcElieceCCA2PublicKey
*/
public int hashCode()
{
- return n + t + g.hashCode();
- }
-
- /**
- * @return the OID of the algorithm
- */
- public String getOIDString()
- {
- return oid;
- }
-
- /**
- * @return the OID to encode in the SubjectPublicKeyInfo structure
- */
- protected ASN1ObjectIdentifier getOID()
- {
- return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
- }
-
- /**
- * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
- * structure
- */
- protected ASN1Primitive getAlgParams()
- {
- return null; // FIXME: needed at all?
+ return 37 * (params.getN() + 37 * params.getT()) + params.getG().hashCode();
}
/**
@@ -196,8 +130,8 @@ public class BCMcElieceCCA2PublicKey
*/
public byte[] getEncoded()
{
- McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
- AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(params.getN(), params.getT(), params.getG(), Utils.getDigAlgId(params.getDigest()));
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2);
try
{
@@ -214,13 +148,11 @@ public class BCMcElieceCCA2PublicKey
public String getFormat()
{
- // TODO Auto-generated method stub
- return null;
+ return "X.509";
}
- public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ AsymmetricKeyParameter getKeyParams()
{
- return McElieceCCA2Params;
+ return params;
}
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
index 32ccd762..8ba02a89 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
@@ -3,21 +3,19 @@ package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
import java.security.PrivateKey;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.asn1.McEliecePrivateKey;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
-import org.bouncycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
import org.bouncycastle.pqc.math.linearalgebra.Permutation;
import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.bouncycastle.util.Strings;
/**
* This class implements a McEliece private key and is usually instantiated by
@@ -32,94 +30,13 @@ public class BCMcEliecePrivateKey
*/
private static final long serialVersionUID = 1L;
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the dimension of the code, where <tt>k &gt;= n - mt</tt>
- private int k;
-
- // the underlying finite field
- private GF2mField field;
-
- // the irreducible Goppa polynomial
- private PolynomialGF2mSmallM goppaPoly;
-
- // the matrix S^-1
- private GF2Matrix sInv;
-
- // the permutation P1 used to generate the systematic check matrix
- private Permutation p1;
-
- // the permutation P2 used to compute the public generator matrix
- private Permutation p2;
-
- // the canonical check matrix of the code
- private GF2Matrix h;
-
- // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
- private PolynomialGF2mSmallM[] qInv;
-
- private McElieceParameters mcElieceParams;
-
-
- /**
- * Constructor (used by the {@link McElieceKeyPairGenerator}).
- *
- * @param oid
- * @param n the length of the code
- * @param k the dimension of the code
- * @param field the field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param goppaPoly the irreducible Goppa polynomial
- * @param sInv the matrix <tt>S<sup>-1</sup></tt>
- * @param p1 the permutation used to generate the systematic check
- * matrix
- * @param p2 the permutation used to compute the public generator
- * matrix
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- */
- public BCMcEliecePrivateKey(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
- Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
- {
- this.oid = oid;
- this.n = n;
- this.k = k;
- this.field = field;
- this.goppaPoly = goppaPoly;
- this.sInv = sInv;
- this.p1 = p1;
- this.p2 = p2;
- this.h = h;
- this.qInv = qInv;
- }
-
- /**
- * Constructor (used by the {@link McElieceKeyFactorySpi}).
- *
- * @param keySpec a {@link McEliecePrivateKeySpec}
- */
- public BCMcEliecePrivateKey(McEliecePrivateKeySpec keySpec)
- {
- this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
- .getGoppaPoly(), keySpec.getSInv(), keySpec.getP1(), keySpec
- .getP2(), keySpec.getH(), keySpec.getQInv());
- }
+ private McEliecePrivateKeyParameters params;
public BCMcEliecePrivateKey(McEliecePrivateKeyParameters params)
{
- this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
- params.getSInv(), params.getP1(), params.getP2(), params.getH(), params.getQInv());
-
- this.mcElieceParams = params.getParameters();
+ this.params = params;
}
-
/**
* Return the name of the algorithm.
*
@@ -135,7 +52,7 @@ public class BCMcEliecePrivateKey
*/
public int getN()
{
- return n;
+ return params.getN();
}
/**
@@ -143,7 +60,7 @@ public class BCMcEliecePrivateKey
*/
public int getK()
{
- return k;
+ return params.getK();
}
/**
@@ -151,7 +68,7 @@ public class BCMcEliecePrivateKey
*/
public GF2mField getField()
{
- return field;
+ return params.getField();
}
/**
@@ -159,7 +76,7 @@ public class BCMcEliecePrivateKey
*/
public PolynomialGF2mSmallM getGoppaPoly()
{
- return goppaPoly;
+ return params.getGoppaPoly();
}
/**
@@ -167,7 +84,7 @@ public class BCMcEliecePrivateKey
*/
public GF2Matrix getSInv()
{
- return sInv;
+ return params.getSInv();
}
/**
@@ -175,7 +92,7 @@ public class BCMcEliecePrivateKey
*/
public Permutation getP1()
{
- return p1;
+ return params.getP1();
}
/**
@@ -183,7 +100,7 @@ public class BCMcEliecePrivateKey
*/
public Permutation getP2()
{
- return p2;
+ return params.getP2();
}
/**
@@ -191,7 +108,7 @@ public class BCMcEliecePrivateKey
*/
public GF2Matrix getH()
{
- return h;
+ return params.getH();
}
/**
@@ -199,15 +116,7 @@ public class BCMcEliecePrivateKey
*/
public PolynomialGF2mSmallM[] getQInv()
{
- return qInv;
- }
-
- /**
- * @return the OID of the algorithm
- */
- public String getOIDString()
- {
- return oid;
+ return params.getQInv();
}
/**
@@ -215,12 +124,12 @@ public class BCMcEliecePrivateKey
*/
public String toString()
{
- String result = " length of the code : " + n + "\n";
- result += " dimension of the code : " + k + "\n";
- result += " irreducible Goppa polynomial: " + goppaPoly + "\n";
- result += " (k x k)-matrix S^-1 : " + sInv + "\n";
- result += " permutation P1 : " + p1 + "\n";
- result += " permutation P2 : " + p2;
+ String result = " length of the code : " + getN() + Strings.lineSeparator();
+ result += " dimension of the code : " + getK() + Strings.lineSeparator();
+ result += " irreducible Goppa polynomial: " + getGoppaPoly() + Strings.lineSeparator();
+ result += " permutation P1 : " + getP1() + Strings.lineSeparator();
+ result += " permutation P2 : " + getP2() + Strings.lineSeparator();
+ result += " (k x k)-matrix S^-1 : " + getSInv();
return result;
}
@@ -238,11 +147,11 @@ public class BCMcEliecePrivateKey
}
BCMcEliecePrivateKey otherKey = (BCMcEliecePrivateKey)other;
- return (n == otherKey.n) && (k == otherKey.k)
- && field.equals(otherKey.field)
- && goppaPoly.equals(otherKey.goppaPoly)
- && sInv.equals(otherKey.sInv) && p1.equals(otherKey.p1)
- && p2.equals(otherKey.p2) && h.equals(otherKey.h);
+ return (getN() == otherKey.getN()) && (getK() == otherKey.getK())
+ && getField().equals(otherKey.getField())
+ && getGoppaPoly().equals(otherKey.getGoppaPoly())
+ && getSInv().equals(otherKey.getSInv()) && getP1().equals(otherKey.getP1())
+ && getP2().equals(otherKey.getP2());
}
/**
@@ -250,26 +159,15 @@ public class BCMcEliecePrivateKey
*/
public int hashCode()
{
- return k + n + field.hashCode() + goppaPoly.hashCode()
- + sInv.hashCode() + p1.hashCode() + p2.hashCode()
- + h.hashCode();
- }
+ int code = params.getK();
- /**
- * @return the OID to encode in the SubjectPublicKeyInfo structure
- */
- protected ASN1ObjectIdentifier getOID()
- {
- return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
- }
+ code = code * 37 + params.getN();
+ code = code * 37 + params.getField().hashCode();
+ code = code * 37 + params.getGoppaPoly().hashCode();
+ code = code * 37 + params.getP1().hashCode();
+ code = code * 37 + params.getP2().hashCode();
- /**
- * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
- * structure
- */
- protected ASN1Primitive getAlgParams()
- {
- return null; // FIXME: needed at all?
+ return code * 37 + params.getSInv().hashCode();
}
/**
@@ -282,7 +180,7 @@ public class BCMcEliecePrivateKey
* n INTEGER -- length of the code
* k INTEGER -- dimension of the code
* fieldPoly OCTET STRING -- field polynomial defining GF(2&circ;m)
- * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * getGoppaPoly() OCTET STRING -- irreducible Goppa polynomial
* sInv OCTET STRING -- matrix S&circ;-1
* p1 OCTET STRING -- permutation P1
* p2 OCTET STRING -- permutation P2
@@ -296,11 +194,11 @@ public class BCMcEliecePrivateKey
*/
public byte[] getEncoded()
{
- McEliecePrivateKey privateKey = new McEliecePrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, sInv, p1, p2, h, qInv);
+ McEliecePrivateKey privateKey = new McEliecePrivateKey(params.getN(), params.getK(), params.getField(), params.getGoppaPoly(), params.getP1(), params.getP2(), params.getSInv());
PrivateKeyInfo pki;
try
{
- AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcEliece);
pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
}
catch (IOException e)
@@ -322,14 +220,11 @@ public class BCMcEliecePrivateKey
public String getFormat()
{
- // TODO Auto-generated method stub
- return null;
+ return "PKCS#8";
}
- public McElieceParameters getMcElieceParameters()
+ AsymmetricKeyParameter getKeyParams()
{
- return mcElieceParams;
+ return params;
}
-
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
index e5b1d22e..e1de3302 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
@@ -3,17 +3,13 @@ package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
import java.security.PublicKey;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.asn1.McEliecePublicKey;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
-import org.bouncycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
/**
@@ -21,64 +17,15 @@ import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
* the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}.
*/
public class BCMcEliecePublicKey
- implements CipherParameters, PublicKey
+ implements PublicKey
{
-
- /**
- *
- */
private static final long serialVersionUID = 1L;
- // the OID of the algorithm
- private String oid;
-
- /**
- * the length of the code
- */
- private int n;
-
- /**
- * the error correction capability of the code
- */
- private int t;
-
- /**
- * the generator matrix
- */
- private GF2Matrix g;
-
- private McElieceParameters McElieceParams;
-
- /**
- * Constructor (used by the {@link McElieceKeyPairGenerator}).
- *
- * @param oid
- * @param n the length of the code
- * @param t the error correction capability of the code
- * @param g the generator matrix
- */
- public BCMcEliecePublicKey(String oid, int n, int t, GF2Matrix g)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.g = g;
- }
-
- /**
- * Constructor (used by the {@link McElieceKeyFactorySpi}).
- *
- * @param keySpec a {@link McEliecePublicKeySpec}
- */
- public BCMcEliecePublicKey(McEliecePublicKeySpec keySpec)
- {
- this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getG());
- }
+ private McEliecePublicKeyParameters params;
public BCMcEliecePublicKey(McEliecePublicKeyParameters params)
{
- this(params.getOIDString(), params.getN(), params.getT(), params.getG());
- this.McElieceParams = params.getParameters();
+ this.params = params;
}
/**
@@ -96,7 +43,7 @@ public class BCMcEliecePublicKey
*/
public int getN()
{
- return n;
+ return params.getN();
}
/**
@@ -104,7 +51,7 @@ public class BCMcEliecePublicKey
*/
public int getK()
{
- return g.getNumRows();
+ return params.getK();
}
/**
@@ -112,7 +59,7 @@ public class BCMcEliecePublicKey
*/
public int getT()
{
- return t;
+ return params.getT();
}
/**
@@ -120,7 +67,7 @@ public class BCMcEliecePublicKey
*/
public GF2Matrix getG()
{
- return g;
+ return params.getG();
}
/**
@@ -129,9 +76,9 @@ public class BCMcEliecePublicKey
public String toString()
{
String result = "McEliecePublicKey:\n";
- result += " length of the code : " + n + "\n";
- result += " error correction capability: " + t + "\n";
- result += " generator matrix : " + g.toString();
+ result += " length of the code : " + params.getN() + "\n";
+ result += " error correction capability: " + params.getT() + "\n";
+ result += " generator matrix : " + params.getG();
return result;
}
@@ -143,13 +90,14 @@ public class BCMcEliecePublicKey
*/
public boolean equals(Object other)
{
- if (!(other instanceof BCMcEliecePublicKey))
+ if (other instanceof BCMcEliecePublicKey)
{
- return false;
+ BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other;
+
+ return (params.getN() == otherKey.getN()) && (params.getT() == otherKey.getT()) && (params.getG().equals(otherKey.getG()));
}
- BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other;
- return (n == otherKey.n) && (t == otherKey.t) && g.equals(otherKey.g);
+ return false;
}
/**
@@ -157,37 +105,10 @@ public class BCMcEliecePublicKey
*/
public int hashCode()
{
- return n + t + g.hashCode();
- }
-
-
- /**
- * @return the OID of the algorithm
- */
- public String getOIDString()
- {
- return oid;
+ return 37 * (params.getN() + 37 * params.getT()) + params.getG().hashCode();
}
/**
- * @return the OID to encode in the SubjectPublicKeyInfo structure
- */
- protected ASN1ObjectIdentifier getOID()
- {
- return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
- }
-
- /**
- * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
- * structure
- */
- protected ASN1Primitive getAlgParams()
- {
- return null; // FIXME: needed at all?
- }
-
-
- /**
* Return the keyData to encode in the SubjectPublicKeyInfo structure.
* <p>
* The ASN.1 definition of the key structure is
@@ -203,8 +124,8 @@ public class BCMcEliecePublicKey
*/
public byte[] getEncoded()
{
- McEliecePublicKey key = new McEliecePublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
- AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ McEliecePublicKey key = new McEliecePublicKey(params.getN(), params.getT(), params.getG());
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcEliece);
try
{
@@ -220,11 +141,11 @@ public class BCMcEliecePublicKey
public String getFormat()
{
- return null;
+ return "X.509";
}
- public McElieceParameters getMcElieceParameters()
+ AsymmetricKeyParameter getKeyParams()
{
- return McElieceParams;
+ return params;
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
index c6ca7c2b..183754ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
@@ -1,7 +1,6 @@
package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
-import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactorySpi;
@@ -12,26 +11,21 @@ import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
-import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey;
import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey;
-import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
-import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
/**
* This class is used to translate between McEliece CCA2 keys and key
* specifications.
*
* @see BCMcElieceCCA2PrivateKey
- * @see McElieceCCA2PrivateKeySpec
* @see BCMcElieceCCA2PublicKey
- * @see McElieceCCA2PublicKeySpec
*/
public class McElieceCCA2KeyFactorySpi
extends KeyFactorySpi
@@ -45,22 +39,17 @@ public class McElieceCCA2KeyFactorySpi
/**
* Converts, if possible, a key specification into a
* {@link BCMcElieceCCA2PublicKey}. Currently, the following key
- * specifications are supported: {@link McElieceCCA2PublicKeySpec},
+ * specifications are supported:
* {@link X509EncodedKeySpec}.
*
* @param keySpec the key specification
* @return the McEliece CCA2 public key
* @throws InvalidKeySpecException if the key specification is not supported.
*/
- public PublicKey generatePublic(KeySpec keySpec)
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
throws InvalidKeySpecException
{
- if (keySpec instanceof McElieceCCA2PublicKeySpec)
- {
- return new BCMcElieceCCA2PublicKey(
- (McElieceCCA2PublicKeySpec)keySpec);
- }
- else if (keySpec instanceof X509EncodedKeySpec)
+ if (keySpec instanceof X509EncodedKeySpec)
{
// get the DER-encoded Key according to X.509 from the spec
byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
@@ -79,27 +68,16 @@ public class McElieceCCA2KeyFactorySpi
try
{
- // --- Build and return the actual key.
- ASN1Primitive innerType = pki.parsePublicKey();
- ASN1Sequence publicKey = (ASN1Sequence)innerType;
-
- // decode oidString (but we don't need it right now)
- String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
- .toString();
-
- // decode <n>
- BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
- int n = bigN.intValue();
-
- // decode <t>
- BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
- int t = bigT.intValue();
-
- // decode <matrixG>
- byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
+ if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getAlgorithm().getAlgorithm()))
+ {
+ McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(pki.parsePublicKey());
- return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeySpec(
- OID, n, t, matrixG));
+ return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeyParameters(key.getN(), key.getT(), key.getG(), Utils.getDigest(key.getDigest()).getAlgorithmName()));
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unable to recognise OID in McEliece private key");
+ }
}
catch (IOException cce)
{
@@ -116,22 +94,17 @@ public class McElieceCCA2KeyFactorySpi
/**
* Converts, if possible, a key specification into a
* {@link BCMcElieceCCA2PrivateKey}. Currently, the following key
- * specifications are supported: {@link McElieceCCA2PrivateKeySpec},
+ * specifications are supported:
* {@link PKCS8EncodedKeySpec}.
*
* @param keySpec the key specification
* @return the McEliece CCA2 private key
* @throws InvalidKeySpecException if the KeySpec is not supported.
*/
- public PrivateKey generatePrivate(KeySpec keySpec)
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException
{
- if (keySpec instanceof McElieceCCA2PrivateKeySpec)
- {
- return new BCMcElieceCCA2PrivateKey(
- (McElieceCCA2PrivateKeySpec)keySpec);
- }
- else if (keySpec instanceof PKCS8EncodedKeySpec)
+ if (keySpec instanceof PKCS8EncodedKeySpec)
{
// get the DER-encoded Key according to PKCS#8 from the spec
byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
@@ -150,47 +123,16 @@ public class McElieceCCA2KeyFactorySpi
try
{
- // get the inner type inside the BIT STRING
- ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
-
- // build and return the actual key
- ASN1Sequence privKey = (ASN1Sequence)innerType;
-
- // decode oidString (but we don't need it right now)
- String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
- .toString();
-
- // decode <n>
- BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
- int n = bigN.intValue();
-
- // decode <k>
- BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
- int k = bigK.intValue();
-
+ if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getPrivateKeyAlgorithm().getAlgorithm()))
+ {
+ McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(pki.parsePrivateKey());
- // decode <fieldPoly>
- byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
- .getOctets();
- // decode <goppaPoly>
- byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
- .getOctets();
- // decode <p>
- byte[] encP = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
- // decode <h>
- byte[] encH = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
- // decode <qInv>
- ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(7);
- byte[][] encQInv = new byte[qSeq.size()][];
- for (int i = 0; i < qSeq.size(); i++)
+ return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), Utils.getDigest(key.getDigest()).getAlgorithmName()));
+ }
+ else
{
- encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ throw new InvalidKeySpecException("Unable to recognise OID in McEliece public key");
}
-
- return new BCMcElieceCCA2PrivateKey(
- new McElieceCCA2PrivateKeySpec(OID, n, k, encFieldPoly,
- encGoppaPoly, encP, encH, encQInv));
-
}
catch (IOException cce)
{
@@ -199,19 +141,12 @@ public class McElieceCCA2KeyFactorySpi
}
}
- throw new InvalidKeySpecException("Unsupported key specification: "
- + keySpec.getClass() + ".");
+ throw new InvalidKeySpecException("Unsupported key specification: " + keySpec.getClass() + ".");
}
/**
* Converts, if possible, a given key into a key specification. Currently,
* the following key specifications are supported:
- * <ul>
- * <li>for McElieceCCA2PublicKey: {@link X509EncodedKeySpec},
- * {@link McElieceCCA2PublicKeySpec}</li>
- * <li>for McElieceCCA2PrivateKey: {@link PKCS8EncodedKeySpec},
- * {@link McElieceCCA2PrivateKeySpec}</li>.
- * </ul>
*
* @param key the key
* @param keySpec the key specification
@@ -219,9 +154,7 @@ public class McElieceCCA2KeyFactorySpi
* @throws InvalidKeySpecException if the key type or the key specification is not
* supported.
* @see BCMcElieceCCA2PrivateKey
- * @see McElieceCCA2PrivateKeySpec
* @see BCMcElieceCCA2PublicKey
- * @see McElieceCCA2PublicKeySpec
*/
public KeySpec getKeySpec(Key key, Class keySpec)
throws InvalidKeySpecException
@@ -232,14 +165,6 @@ public class McElieceCCA2KeyFactorySpi
{
return new PKCS8EncodedKeySpec(key.getEncoded());
}
- else if (McElieceCCA2PrivateKeySpec.class
- .isAssignableFrom(keySpec))
- {
- BCMcElieceCCA2PrivateKey privKey = (BCMcElieceCCA2PrivateKey)key;
- return new McElieceCCA2PrivateKeySpec(OID, privKey.getN(), privKey
- .getK(), privKey.getField(), privKey.getGoppaPoly(),
- privKey.getP(), privKey.getH(), privKey.getQInv());
- }
}
else if (key instanceof BCMcElieceCCA2PublicKey)
{
@@ -247,13 +172,6 @@ public class McElieceCCA2KeyFactorySpi
{
return new X509EncodedKeySpec(key.getEncoded());
}
- else if (McElieceCCA2PublicKeySpec.class
- .isAssignableFrom(keySpec))
- {
- BCMcElieceCCA2PublicKey pubKey = (BCMcElieceCCA2PublicKey)key;
- return new McElieceCCA2PublicKeySpec(OID, pubKey.getN(), pubKey
- .getT(), pubKey.getG());
- }
}
else
{
@@ -294,8 +212,8 @@ public class McElieceCCA2KeyFactorySpi
try
{
ASN1Primitive innerType = pki.parsePublicKey();
- McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance((ASN1Sequence)innerType);
- return new BCMcElieceCCA2PublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(innerType);
+ return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeyParameters(key.getN(), key.getT(), key.getG(), Utils.getDigest(key.getDigest()).getAlgorithmName()));
}
catch (IOException cce)
{
@@ -312,7 +230,7 @@ public class McElieceCCA2KeyFactorySpi
{
ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType);
- return new BCMcElieceCCA2PrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), key.getH(), key.getQInv());
+ return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), null));
}
catch (IOException cce)
{
@@ -320,18 +238,6 @@ public class McElieceCCA2KeyFactorySpi
}
}
- protected PublicKey engineGeneratePublic(KeySpec keySpec)
- throws InvalidKeySpecException
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
- throws InvalidKeySpecException
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
protected KeySpec engineGetKeySpec(Key key, Class tClass)
throws InvalidKeySpecException
{
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java
new file mode 100644
index 00000000..2de91413
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
+
+public class McElieceCCA2KeyPairGeneratorSpi
+ extends KeyPairGenerator
+{
+ private McElieceCCA2KeyPairGenerator kpg;
+
+ public McElieceCCA2KeyPairGeneratorSpi()
+ {
+ super("McEliece-CCA2");
+ }
+
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ kpg = new McElieceCCA2KeyPairGenerator();
+ super.initialize(params);
+ McElieceCCA2KeyGenParameterSpec ecc = (McElieceCCA2KeyGenParameterSpec)params;
+
+ McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT(), ecc.getDigest()));
+ kpg.init(mccca2KGParams);
+ }
+
+ public void initialize(int keySize, SecureRandom random)
+ {
+ kpg = new McElieceCCA2KeyPairGenerator();
+
+ McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(random, new McElieceCCA2Parameters());
+ kpg.init(mccca2KGParams);
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McElieceCCA2PrivateKeyParameters sk = (McElieceCCA2PrivateKeyParameters)generateKeyPair.getPrivate();
+ McElieceCCA2PublicKeyParameters pk = (McElieceCCA2PublicKeyParameters)generateKeyPair.getPublic();
+
+ return new KeyPair(new BCMcElieceCCA2PublicKey(pk), new BCMcElieceCCA2PrivateKey(sk));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
index 03e7c1b9..39785509 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
@@ -5,8 +5,6 @@ import java.security.PrivateKey;
import java.security.PublicKey;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
/**
* utility class for converting jce/jca McElieceCCA2 objects
@@ -24,7 +22,7 @@ public class McElieceCCA2KeysToParams
{
BCMcElieceCCA2PublicKey k = (BCMcElieceCCA2PublicKey)key;
- return new McElieceCCA2PublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceCCA2Parameters());
+ return k.getKeyParams();
}
throw new InvalidKeyException("can't identify McElieceCCA2 public key: " + key.getClass().getName());
@@ -38,8 +36,8 @@ public class McElieceCCA2KeysToParams
if (key instanceof BCMcElieceCCA2PrivateKey)
{
BCMcElieceCCA2PrivateKey k = (BCMcElieceCCA2PrivateKey)key;
- return new McElieceCCA2PrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
- k.getP(), k.getH(), k.getQInv(), k.getMcElieceCCA2Parameters());
+
+ return k.getKeyParams();
}
throw new InvalidKeyException("can't identify McElieceCCA2 private key.");
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
index 2650fffe..7f2115c3 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
@@ -44,7 +44,7 @@ public final class McElieceCCA2Primitives
GF2Vector m, GF2Vector z)
{
- GF2Matrix matrixG = pubKey.getMatrixG();
+ GF2Matrix matrixG = pubKey.getG();
Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
return (GF2Vector)mG.add(z);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
index 5320c220..e2f18101 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
@@ -18,11 +18,8 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiCipher;
import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
@@ -209,45 +206,7 @@ public class McElieceFujisakiCipherSpi
{
public McElieceFujisaki()
{
- super(new SHA1Digest(), new McElieceFujisakiCipher());
+ super(DigestFactory.createSHA1(), new McElieceFujisakiCipher());
}
}
-
- static public class McElieceFujisaki224
- extends McElieceFujisakiCipherSpi
- {
- public McElieceFujisaki224()
- {
- super(new SHA224Digest(), new McElieceFujisakiCipher());
- }
- }
-
- static public class McElieceFujisaki256
- extends McElieceFujisakiCipherSpi
- {
- public McElieceFujisaki256()
- {
- super(new SHA256Digest(), new McElieceFujisakiCipher());
- }
- }
-
- static public class McElieceFujisaki384
- extends McElieceFujisakiCipherSpi
- {
- public McElieceFujisaki384()
- {
- super(new SHA384Digest(), new McElieceFujisakiCipher());
- }
- }
-
- static public class McElieceFujisaki512
- extends McElieceFujisakiCipherSpi
- {
- public McElieceFujisaki512()
- {
- super(new SHA512Digest(), new McElieceFujisakiCipher());
- }
- }
-
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
index c1df9e94..85f718d5 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
@@ -1,7 +1,6 @@
package org.bouncycastle.pqc.jcajce.provider.mceliece;
import java.io.IOException;
-import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactorySpi;
@@ -12,25 +11,23 @@ import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
-import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.pqc.asn1.McEliecePrivateKey;
import org.bouncycastle.pqc.asn1.McEliecePublicKey;
-import org.bouncycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
-import org.bouncycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
/**
* This class is used to translate between McEliece keys and key specifications.
*
* @see BCMcEliecePrivateKey
- * @see McEliecePrivateKeySpec
* @see BCMcEliecePublicKey
- * @see McEliecePublicKeySpec
*/
public class McElieceKeyFactorySpi
extends KeyFactorySpi
@@ -42,21 +39,16 @@ public class McElieceKeyFactorySpi
/**
* Converts, if possible, a key specification into a
- * {@link BCMcEliecePublicKey}. Currently, the following key specifications
- * are supported: {@link McEliecePublicKeySpec}, {@link X509EncodedKeySpec}.
+ * {@link BCMcEliecePublicKey}. {@link X509EncodedKeySpec}.
*
* @param keySpec the key specification
* @return the McEliece public key
* @throws InvalidKeySpecException if the key specification is not supported.
*/
- public PublicKey generatePublic(KeySpec keySpec)
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
throws InvalidKeySpecException
{
- if (keySpec instanceof McEliecePublicKeySpec)
- {
- return new BCMcEliecePublicKey((McEliecePublicKeySpec)keySpec);
- }
- else if (keySpec instanceof X509EncodedKeySpec)
+ if (keySpec instanceof X509EncodedKeySpec)
{
// get the DER-encoded Key according to X.509 from the spec
byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
@@ -74,28 +66,16 @@ public class McElieceKeyFactorySpi
try
{
- // --- Build and return the actual key.
- ASN1Primitive innerType = pki.parsePublicKey();
- ASN1Sequence publicKey = (ASN1Sequence)innerType;
-
- // decode oidString (but we don't need it right now)
- String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
- .toString();
-
- // decode <n>
- BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
- int n = bigN.intValue();
-
- // decode <t>
- BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
- int t = bigT.intValue();
-
- // decode <matrixG>
- byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
-
+ if (PQCObjectIdentifiers.mcEliece.equals(pki.getAlgorithm().getAlgorithm()))
+ {
+ McEliecePublicKey key = McEliecePublicKey.getInstance(pki.parsePublicKey());
- return new BCMcEliecePublicKey(new McEliecePublicKeySpec(OID, t, n,
- matrixG));
+ return new BCMcEliecePublicKey(new McEliecePublicKeyParameters(key.getN(), key.getT(), key.getG()));
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unable to recognise OID in McEliece public key");
+ }
}
catch (IOException cce)
{
@@ -111,22 +91,16 @@ public class McElieceKeyFactorySpi
/**
* Converts, if possible, a key specification into a
- * {@link BCMcEliecePrivateKey}. Currently, the following key specifications
- * are supported: {@link McEliecePrivateKeySpec},
- * {@link PKCS8EncodedKeySpec}.
+ * {@link BCMcEliecePrivateKey}.
*
* @param keySpec the key specification
* @return the McEliece private key
* @throws InvalidKeySpecException if the KeySpec is not supported.
*/
- public PrivateKey generatePrivate(KeySpec keySpec)
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException
{
- if (keySpec instanceof McEliecePrivateKeySpec)
- {
- return new BCMcEliecePrivateKey((McEliecePrivateKeySpec)keySpec);
- }
- else if (keySpec instanceof PKCS8EncodedKeySpec)
+ if (keySpec instanceof PKCS8EncodedKeySpec)
{
// get the DER-encoded Key according to PKCS#8 from the spec
byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
@@ -145,52 +119,16 @@ public class McElieceKeyFactorySpi
try
{
- ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
-
- // build and return the actual key
- ASN1Sequence privKey = (ASN1Sequence)innerType;
-
- // decode oidString (but we don't need it right now)
- String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
- .toString();
-
- // decode <n>
- BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
- int n = bigN.intValue();
-
- // decode <k>
- BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
- int k = bigK.intValue();
-
- // decode <fieldPoly>
- byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
- .getOctets();
- // decode <goppaPoly>
- byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
- .getOctets();
-
- // decode <sInv>
- byte[] encSInv = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
- // decode <p1>
- byte[] encP1 = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
- // decode <p2>
- byte[] encP2 = ((ASN1OctetString)privKey.getObjectAt(7)).getOctets();
-
- //decode <h>
- byte[] encH = ((ASN1OctetString)privKey.getObjectAt(8)).getOctets();
+ if (PQCObjectIdentifiers.mcEliece.equals(pki.getPrivateKeyAlgorithm().getAlgorithm()))
+ {
+ McEliecePrivateKey key = McEliecePrivateKey.getInstance(pki.parsePrivateKey());
- // decode <qInv>
- ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(9);
- byte[][] encQInv = new byte[qSeq.size()][];
- for (int i = 0; i < qSeq.size(); i++)
+ return new BCMcEliecePrivateKey(new McEliecePrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP1(), key.getP2(), key.getSInv()));
+ }
+ else
{
- encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ throw new InvalidKeySpecException("Unable to recognise OID in McEliece private key");
}
-
- return new BCMcEliecePrivateKey(new McEliecePrivateKeySpec(OID, n, k,
- encFieldPoly, encGoppaPoly, encSInv, encP1, encP2,
- encH, encQInv));
-
}
catch (IOException cce)
{
@@ -206,12 +144,6 @@ public class McElieceKeyFactorySpi
/**
* Converts, if possible, a given key into a key specification. Currently,
* the following key specifications are supported:
- * <ul>
- * <li>for McEliecePublicKey: {@link X509EncodedKeySpec},
- * {@link McEliecePublicKeySpec}</li>
- * <li>for McEliecePrivateKey: {@link PKCS8EncodedKeySpec},
- * {@link McEliecePrivateKeySpec}</li>.
- * </ul>
*
* @param key the key
* @param keySpec the key specification
@@ -219,9 +151,7 @@ public class McElieceKeyFactorySpi
* @throws InvalidKeySpecException if the key type or the key specification is not
* supported.
* @see BCMcEliecePrivateKey
- * @see McEliecePrivateKeySpec
* @see BCMcEliecePublicKey
- * @see McEliecePublicKeySpec
*/
public KeySpec getKeySpec(Key key, Class keySpec)
throws InvalidKeySpecException
@@ -232,14 +162,6 @@ public class McElieceKeyFactorySpi
{
return new PKCS8EncodedKeySpec(key.getEncoded());
}
- else if (McEliecePrivateKeySpec.class.isAssignableFrom(keySpec))
- {
- BCMcEliecePrivateKey privKey = (BCMcEliecePrivateKey)key;
- return new McEliecePrivateKeySpec(OID, privKey.getN(), privKey
- .getK(), privKey.getField(), privKey.getGoppaPoly(),
- privKey.getSInv(), privKey.getP1(), privKey.getP2(),
- privKey.getH(), privKey.getQInv());
- }
}
else if (key instanceof BCMcEliecePublicKey)
{
@@ -247,12 +169,6 @@ public class McElieceKeyFactorySpi
{
return new X509EncodedKeySpec(key.getEncoded());
}
- else if (McEliecePublicKeySpec.class.isAssignableFrom(keySpec))
- {
- BCMcEliecePublicKey pubKey = (BCMcEliecePublicKey)key;
- return new McEliecePublicKeySpec(OID, pubKey.getN(), pubKey.getT(),
- pubKey.getG());
- }
}
else
{
@@ -293,7 +209,7 @@ public class McElieceKeyFactorySpi
{
ASN1Primitive innerType = pki.parsePublicKey();
McEliecePublicKey key = McEliecePublicKey.getInstance(innerType);
- return new BCMcEliecePublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ return new BCMcEliecePublicKey(new McEliecePublicKeyParameters(key.getN(), key.getT(), key.getG()));
}
catch (IOException cce)
{
@@ -309,7 +225,7 @@ public class McElieceKeyFactorySpi
{
ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
McEliecePrivateKey key = McEliecePrivateKey.getInstance(innerType);
- return new BCMcEliecePrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getSInv(), key.getP1(), key.getP2(), key.getH(), key.getQInv());
+ return new BCMcEliecePrivateKey(new McEliecePrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP1(), key.getP2(), key.getSInv()));
}
catch (IOException cce)
{
@@ -317,18 +233,6 @@ public class McElieceKeyFactorySpi
}
}
- protected PublicKey engineGeneratePublic(KeySpec keySpec)
- throws InvalidKeySpecException
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
- protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
- throws InvalidKeySpecException
- {
- return null; //To change body of implemented methods use File | Settings | File Templates.
- }
-
protected KeySpec engineGetKeySpec(Key key, Class tClass)
throws InvalidKeySpecException
{
@@ -340,4 +244,9 @@ public class McElieceKeyFactorySpi
{
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+
+ private static Digest getDigest(AlgorithmIdentifier algId)
+ {
+ return new SHA256Digest();
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
index 75008fef..f5e349c2 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
@@ -7,140 +7,55 @@ import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
-import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
import org.bouncycastle.pqc.crypto.mceliece.McElieceParameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
-import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2ParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec;
-public abstract class McElieceKeyPairGeneratorSpi
+public class McElieceKeyPairGeneratorSpi
extends KeyPairGenerator
{
- public McElieceKeyPairGeneratorSpi(
- String algorithmName)
+ McElieceKeyPairGenerator kpg;
+
+ public McElieceKeyPairGeneratorSpi()
{
- super(algorithmName);
+ super("McEliece");
}
- /**
- *
- *
- *
- */
-
- public static class McElieceCCA2
- extends McElieceKeyPairGeneratorSpi
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
{
+ kpg = new McElieceKeyPairGenerator();
+ super.initialize(params);
+ McElieceKeyGenParameterSpec ecc = (McElieceKeyGenParameterSpec)params;
- McElieceCCA2KeyPairGenerator kpg;
-
-
- public McElieceCCA2()
- {
- super("McElieceCCA-2");
- }
-
- public McElieceCCA2(String s)
- {
- super(s);
- }
-
- public void initialize(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException
- {
- kpg = new McElieceCCA2KeyPairGenerator();
- super.initialize(params);
- ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
-
- McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT()));
- kpg.init(mccca2KGParams);
- }
-
- public void initialize(int keySize, SecureRandom random)
- {
- McElieceCCA2ParameterSpec paramSpec = new McElieceCCA2ParameterSpec();
-
- // call the initializer with the chosen parameters
- try
- {
- this.initialize(paramSpec);
- }
- catch (InvalidAlgorithmParameterException ae)
- {
- }
- }
-
- public KeyPair generateKeyPair()
- {
- AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
- McElieceCCA2PrivateKeyParameters sk = (McElieceCCA2PrivateKeyParameters)generateKeyPair.getPrivate();
- McElieceCCA2PublicKeyParameters pk = (McElieceCCA2PublicKeyParameters)generateKeyPair.getPublic();
-
- return new KeyPair(new BCMcElieceCCA2PublicKey(pk), new BCMcElieceCCA2PrivateKey(sk));
-
- }
-
+ McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT()));
+ kpg.init(mccKGParams);
}
- /**
- *
- *
- *
- */
-
- public static class McEliece
- extends McElieceKeyPairGeneratorSpi
+ public void initialize(int keySize, SecureRandom random)
{
+ McElieceKeyGenParameterSpec paramSpec = new McElieceKeyGenParameterSpec();
- McElieceKeyPairGenerator kpg;
-
-
- public McEliece()
- {
- super("McEliece");
- }
-
- public void initialize(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException
+ // call the initializer with the chosen parameters
+ try
{
- kpg = new McElieceKeyPairGenerator();
- super.initialize(params);
- ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
-
- McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT()));
- kpg.init(mccKGParams);
+ this.initialize(paramSpec);
}
-
- public void initialize(int keySize, SecureRandom random)
+ catch (InvalidAlgorithmParameterException ae)
{
- ECCKeyGenParameterSpec paramSpec = new ECCKeyGenParameterSpec();
-
- // call the initializer with the chosen parameters
- try
- {
- this.initialize(paramSpec);
- }
- catch (InvalidAlgorithmParameterException ae)
- {
- }
}
+ }
- public KeyPair generateKeyPair()
- {
- AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
- McEliecePrivateKeyParameters sk = (McEliecePrivateKeyParameters)generateKeyPair.getPrivate();
- McEliecePublicKeyParameters pk = (McEliecePublicKeyParameters)generateKeyPair.getPublic();
-
- return new KeyPair(new BCMcEliecePublicKey(pk), new BCMcEliecePrivateKey(sk));
- }
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McEliecePrivateKeyParameters sk = (McEliecePrivateKeyParameters)generateKeyPair.getPrivate();
+ McEliecePublicKeyParameters pk = (McEliecePublicKeyParameters)generateKeyPair.getPublic();
+ return new KeyPair(new BCMcEliecePublicKey(pk), new BCMcEliecePrivateKey(sk));
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
index 23686b8c..c4142609 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
@@ -6,7 +6,6 @@ import java.security.PublicKey;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
-import org.bouncycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
/**
* utility class for converting jce/jca McEliece objects
@@ -24,7 +23,7 @@ public class McElieceKeysToParams
{
BCMcEliecePublicKey k = (BCMcEliecePublicKey)key;
- return new McEliecePublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceParameters());
+ return k.getKeyParams();
}
throw new InvalidKeyException("can't identify McEliece public key: " + key.getClass().getName());
@@ -38,8 +37,8 @@ public class McElieceKeysToParams
if (key instanceof BCMcEliecePrivateKey)
{
BCMcEliecePrivateKey k = (BCMcEliecePrivateKey)key;
- return new McEliecePrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
- k.getSInv(), k.getP1(), k.getP2(), k.getH(), k.getQInv(), k.getMcElieceParameters());
+ return new McEliecePrivateKeyParameters(k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
+ k.getP1(), k.getP2(), k.getSInv());
}
throw new InvalidKeyException("can't identify McEliece private key.");
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
index 36c62312..0a1df2a1 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
@@ -23,6 +23,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
@@ -263,7 +264,7 @@ public class McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai()
{
- super(new SHA1Digest(), new McElieceKobaraImaiCipher());
+ super(DigestFactory.createSHA1(), new McElieceKobaraImaiCipher());
}
}
@@ -272,7 +273,7 @@ public class McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai224()
{
- super(new SHA224Digest(), new McElieceKobaraImaiCipher());
+ super(DigestFactory.createSHA224(), new McElieceKobaraImaiCipher());
}
}
@@ -281,7 +282,7 @@ public class McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai256()
{
- super(new SHA256Digest(), new McElieceKobaraImaiCipher());
+ super(DigestFactory.createSHA256(), new McElieceKobaraImaiCipher());
}
}
@@ -290,7 +291,7 @@ public class McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai384()
{
- super(new SHA384Digest(), new McElieceKobaraImaiCipher());
+ super(DigestFactory.createSHA384(), new McElieceKobaraImaiCipher());
}
}
@@ -299,7 +300,7 @@ public class McElieceKobaraImaiCipherSpi
{
public McElieceKobaraImai512()
{
- super(new SHA512Digest(), new McElieceKobaraImaiCipher());
+ super(DigestFactory.createSHA512(), new McElieceKobaraImaiCipher());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
index 583acbba..e4ff43f2 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
@@ -14,28 +14,19 @@ import javax.crypto.IllegalBlockSizeException;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA224Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.mceliece.McElieceCipher;
import org.bouncycastle.pqc.crypto.mceliece.McElieceKeyParameters;
-import org.bouncycastle.pqc.crypto.mceliece.McEliecePKCSCipher;
import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricBlockCipher;
public class McEliecePKCSCipherSpi
extends AsymmetricBlockCipher
implements PKCSObjectIdentifiers, X509ObjectIdentifiers
{
- // TODO digest needed?
- private Digest digest;
- private McEliecePKCSCipher cipher;
+ private McElieceCipher cipher;
- public McEliecePKCSCipherSpi(Digest digest, McEliecePKCSCipher cipher)
+ public McEliecePKCSCipherSpi(McElieceCipher cipher)
{
- this.digest = digest;
this.cipher = cipher;
}
@@ -49,7 +40,6 @@ public class McEliecePKCSCipherSpi
param = McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key);
param = new ParametersWithRandom(param, sr);
- digest.reset();
cipher.init(true, param);
this.maxPlainTextSize = cipher.maxPlainTextSize;
this.cipherTextSize = cipher.cipherTextSize;
@@ -61,7 +51,6 @@ public class McEliecePKCSCipherSpi
CipherParameters param;
param = McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key);
- digest.reset();
cipher.init(false, param);
this.maxPlainTextSize = cipher.maxPlainTextSize;
this.cipherTextSize = cipher.cipherTextSize;
@@ -120,52 +109,12 @@ public class McEliecePKCSCipherSpi
return cipher.getKeySize(mcElieceKeyParameters);
}
- //////////////////////////////////////////////////////////////////////////////////
-
static public class McEliecePKCS
extends McEliecePKCSCipherSpi
{
public McEliecePKCS()
{
- super(new SHA1Digest(), new McEliecePKCSCipher());
- }
- }
-
- static public class McEliecePKCS224
- extends McEliecePKCSCipherSpi
- {
- public McEliecePKCS224()
- {
- super(new SHA224Digest(), new McEliecePKCSCipher());
+ super(new McElieceCipher());
}
}
-
- static public class McEliecePKCS256
- extends McEliecePKCSCipherSpi
- {
- public McEliecePKCS256()
- {
- super(new SHA256Digest(), new McEliecePKCSCipher());
- }
- }
-
- static public class McEliecePKCS384
- extends McEliecePKCSCipherSpi
- {
- public McEliecePKCS384()
- {
- super(new SHA384Digest(), new McEliecePKCSCipher());
- }
- }
-
- static public class McEliecePKCS512
- extends McEliecePKCSCipherSpi
- {
- public McEliecePKCS512()
- {
- super(new SHA512Digest(), new McEliecePKCSCipher());
- }
- }
-
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
index c9c67ea6..f4db11db 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
@@ -23,6 +23,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
import org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalCipher;
import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
@@ -203,7 +204,7 @@ public class McEliecePointchevalCipherSpi
{
public McEliecePointcheval()
{
- super(new SHA1Digest(), new McEliecePointchevalCipher());
+ super(DigestFactory.createSHA1(), new McEliecePointchevalCipher());
}
}
@@ -212,7 +213,7 @@ public class McEliecePointchevalCipherSpi
{
public McEliecePointcheval224()
{
- super(new SHA224Digest(), new McEliecePointchevalCipher());
+ super(DigestFactory.createSHA224(), new McEliecePointchevalCipher());
}
}
@@ -221,7 +222,7 @@ public class McEliecePointchevalCipherSpi
{
public McEliecePointcheval256()
{
- super(new SHA256Digest(), new McEliecePointchevalCipher());
+ super(DigestFactory.createSHA256(), new McEliecePointchevalCipher());
}
}
@@ -230,7 +231,7 @@ public class McEliecePointchevalCipherSpi
{
public McEliecePointcheval384()
{
- super(new SHA384Digest(), new McEliecePointchevalCipher());
+ super(DigestFactory.createSHA384(), new McEliecePointchevalCipher());
}
}
@@ -239,7 +240,7 @@ public class McEliecePointchevalCipherSpi
{
public McEliecePointcheval512()
{
- super(new SHA512Digest(), new McEliecePointchevalCipher());
+ super(DigestFactory.createSHA512(), new McEliecePointchevalCipher());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java
new file mode 100644
index 00000000..7037d160
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.pqc.jcajce.provider.mceliece;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.util.DigestFactory;
+
+class Utils
+{
+ static AlgorithmIdentifier getDigAlgId(String digestName)
+ {
+ if (digestName.equals("SHA-1"))
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ }
+ if (digestName.equals("SHA-224"))
+ {
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ }
+ if (digestName.equals("SHA-256"))
+ {
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ }
+ if (digestName.equals("SHA-384"))
+ {
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ }
+ if (digestName.equals("SHA-512"))
+ {
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ }
+
+ throw new IllegalArgumentException("unrecognised digest algorithm: " + digestName);
+ }
+
+ static Digest getDigest(AlgorithmIdentifier digest)
+ {
+ if (digest.getAlgorithm().equals(OIWObjectIdentifiers.idSHA1))
+ {
+ return DigestFactory.createSHA1();
+ }
+ if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha224))
+ {
+ return DigestFactory.createSHA224();
+ }
+ if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha256))
+ {
+ return DigestFactory.createSHA256();
+ }
+ if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha384))
+ {
+ return DigestFactory.createSHA384();
+ }
+ if (digest.getAlgorithm().equals(NISTObjectIdentifiers.id_sha512))
+ {
+ return DigestFactory.createSHA512();
+ }
+ throw new IllegalArgumentException("unrecognised OID in digest algorithm identifier: " + digest.getAlgorithm());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java
new file mode 100644
index 00000000..1e76d0dc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java
@@ -0,0 +1,116 @@
+package org.bouncycastle.pqc.jcajce.provider.newhope;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
+import org.bouncycastle.pqc.jcajce.interfaces.NHPrivateKey;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
+
+public class BCNHPrivateKey
+ implements NHPrivateKey
+{
+ private static final long serialVersionUID = 1L;
+ ;
+ private final NHPrivateKeyParameters params;
+
+ public BCNHPrivateKey(
+ NHPrivateKeyParameters params)
+ {
+ this.params = params;
+ }
+
+ public BCNHPrivateKey(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ this.params = new NHPrivateKeyParameters(convert(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets()));
+ }
+
+ /**
+ * Compare this NH private key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof BCNHPrivateKey))
+ {
+ return false;
+ }
+ BCNHPrivateKey otherKey = (BCNHPrivateKey)o;
+
+ return Arrays.areEqual(params.getSecData(), otherKey.params.getSecData());
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(params.getSecData());
+ }
+
+ /**
+ * @return name of the algorithm - "NH"
+ */
+ public final String getAlgorithm()
+ {
+ return "NH";
+ }
+
+ public byte[] getEncoded()
+ {
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope);
+
+ short[] privateKeyData = params.getSecData();
+
+ byte[] octets = new byte[privateKeyData.length * 2];
+ for (int i = 0; i != privateKeyData.length; i++)
+ {
+ Pack.shortToLittleEndian(privateKeyData[i], octets, i * 2);
+ }
+
+ pki = new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(octets));
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public short[] getSecretData()
+ {
+ return params.getSecData();
+ }
+
+ CipherParameters getKeyParams()
+ {
+ return params;
+ }
+
+ private static short[] convert(byte[] octets)
+ {
+ short[] rv = new short[octets.length / 2];
+
+ for (int i = 0; i != rv.length; i++)
+ {
+ rv[i] = Pack.littleEndianToShort(octets, i * 2);
+ }
+
+ return rv;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java
new file mode 100644
index 00000000..eec1fcd9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.pqc.jcajce.provider.newhope;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
+import org.bouncycastle.pqc.jcajce.interfaces.NHPublicKey;
+import org.bouncycastle.util.Arrays;
+
+public class BCNHPublicKey
+ implements NHPublicKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private final NHPublicKeyParameters params;
+
+ public BCNHPublicKey(
+ NHPublicKeyParameters params)
+ {
+ this.params = params;
+ }
+
+ public BCNHPublicKey(SubjectPublicKeyInfo keyInfo)
+ {
+ this.params = new NHPublicKeyParameters(keyInfo.getPublicKeyData().getBytes());
+ }
+
+ /**
+ * Compare this SPHINCS-256 public key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof BCNHPublicKey))
+ {
+ return false;
+ }
+ BCNHPublicKey otherKey = (BCNHPublicKey)o;
+
+ return Arrays.areEqual(params.getPubData(), otherKey.params.getPubData());
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(params.getPubData());
+ }
+
+ /**
+ * @return name of the algorithm - "NH"
+ */
+ public final String getAlgorithm()
+ {
+ return "NH";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope);
+ pki = new SubjectPublicKeyInfo(algorithmIdentifier, params.getPubData());
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getPublicData()
+ {
+ return params.getPubData();
+ }
+
+ CipherParameters getKeyParams()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/KeyAgreementSpi.java
new file mode 100644
index 00000000..a51a2971
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/KeyAgreementSpi.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.pqc.jcajce.provider.newhope;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.ShortBufferException;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
+import org.bouncycastle.pqc.crypto.ExchangePair;
+import org.bouncycastle.pqc.crypto.newhope.NHAgreement;
+import org.bouncycastle.pqc.crypto.newhope.NHExchangePairGenerator;
+import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
+import org.bouncycastle.util.Arrays;
+
+public class KeyAgreementSpi
+ extends BaseAgreementSpi
+{
+ private NHAgreement agreement;
+ private BCNHPublicKey otherPartyKey;
+ private NHExchangePairGenerator exchangePairGenerator;
+
+ private byte[] shared;
+
+ public KeyAgreementSpi()
+ {
+ super("NH", null);
+ }
+
+ protected void engineInit(Key key, SecureRandom secureRandom)
+ throws InvalidKeyException
+ {
+ if (key != null)
+ {
+ agreement = new NHAgreement();
+
+ agreement.init(((BCNHPrivateKey)key).getKeyParams());
+ }
+ else
+ {
+ exchangePairGenerator = new NHExchangePairGenerator(secureRandom);
+ }
+ }
+
+ protected void engineInit(Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("NewHope does not require parameters");
+ }
+
+ protected Key engineDoPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (!lastPhase)
+ {
+ throw new IllegalStateException("NewHope can only be between two parties.");
+ }
+
+ otherPartyKey = (BCNHPublicKey)key;
+
+ if (exchangePairGenerator != null)
+ {
+ ExchangePair exchPair = exchangePairGenerator.GenerateExchange((AsymmetricKeyParameter)otherPartyKey.getKeyParams());
+
+ shared = exchPair.getSharedValue();
+
+ return new BCNHPublicKey((NHPublicKeyParameters)exchPair.getPublicKey());
+ }
+ else
+ {
+ shared = agreement.calculateAgreement(otherPartyKey.getKeyParams());
+
+ return null;
+ }
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ byte[] rv = Arrays.clone(shared);
+
+ Arrays.fill(shared, (byte)0);
+
+ return rv;
+ }
+
+ protected int engineGenerateSecret(byte[] bytes, int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ System.arraycopy(shared, 0, bytes, offset, shared.length);
+
+ Arrays.fill(shared, (byte)0);
+
+ return shared.length;
+ }
+
+ protected byte[] calcSecret()
+ {
+ return engineGenerateSecret();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyFactorySpi.java
new file mode 100644
index 00000000..179eca75
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyFactorySpi.java
@@ -0,0 +1,116 @@
+package org.bouncycastle.pqc.jcajce.provider.newhope;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class NHKeyFactorySpi
+ extends KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ public PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ public PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
+ }
+
+ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCNHPrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else if (key instanceof BCNHPublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ public final Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCNHPrivateKey || key instanceof BCNHPublicKey)
+ {
+ return key;
+ }
+
+ throw new InvalidKeyException("Unsupported key type");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCNHPrivateKey(keyInfo);
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCNHPublicKey(keyInfo);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java
new file mode 100644
index 00000000..ad35cf17
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/newhope/NHKeyPairGeneratorSpi.java
@@ -0,0 +1,61 @@
+package org.bouncycastle.pqc.jcajce.provider.newhope;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.newhope.NHKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
+
+public class NHKeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ NHKeyPairGenerator engine = new NHKeyPairGenerator();
+
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public NHKeyPairGeneratorSpi()
+ {
+ super("NH");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ if (strength != 1024)
+ {
+ throw new IllegalArgumentException("strength must be 1024 bits");
+ }
+ engine.init(new KeyGenerationParameters(random, 1024));
+ initialised = true;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not recognised");
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ engine.init(new KeyGenerationParameters(random, 1024));
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ NHPublicKeyParameters pub = (NHPublicKeyParameters)pair.getPublic();
+ NHPrivateKeyParameters priv = (NHPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCNHPublicKey(pub), new BCNHPrivateKey(priv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java
new file mode 100644
index 00000000..d5a1c06c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.pqc.jcajce.provider.sphincs;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import org.bouncycastle.pqc.jcajce.interfaces.SPHINCSKey;
+import org.bouncycastle.util.Arrays;
+
+public class BCSphincs256PrivateKey
+ implements PrivateKey, SPHINCSKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private final ASN1ObjectIdentifier treeDigest;
+ private final SPHINCSPrivateKeyParameters params;
+
+ public BCSphincs256PrivateKey(
+ ASN1ObjectIdentifier treeDigest,
+ SPHINCSPrivateKeyParameters params)
+ {
+ this.treeDigest = treeDigest;
+ this.params = params;
+ }
+
+ public BCSphincs256PrivateKey(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ this.treeDigest = SPHINCS256KeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()).getTreeDigest().getAlgorithm();
+ this.params = new SPHINCSPrivateKeyParameters(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets());
+ }
+
+ /**
+ * Compare this SPHINCS-256 private key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof BCSphincs256PrivateKey))
+ {
+ return false;
+ }
+ BCSphincs256PrivateKey otherKey = (BCSphincs256PrivateKey)o;
+
+ return treeDigest.equals(otherKey.treeDigest) && Arrays.areEqual(params.getKeyData(), otherKey.params.getKeyData());
+ }
+
+ public int hashCode()
+ {
+ return treeDigest.hashCode() + 37 * Arrays.hashCode(params.getKeyData());
+ }
+
+ /**
+ * @return name of the algorithm - "SPHINCS-256"
+ */
+ public final String getAlgorithm()
+ {
+ return "SPHINCS-256";
+ }
+
+ public byte[] getEncoded()
+ {
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest)));
+ pki = new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getKeyData()));
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getKeyData()
+ {
+ return params.getKeyData();
+ }
+
+ CipherParameters getKeyParams()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java
new file mode 100644
index 00000000..ee98686b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.pqc.jcajce.provider.sphincs;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import org.bouncycastle.pqc.jcajce.interfaces.SPHINCSKey;
+import org.bouncycastle.util.Arrays;
+
+public class BCSphincs256PublicKey
+ implements PublicKey, SPHINCSKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private final ASN1ObjectIdentifier treeDigest;
+ private final SPHINCSPublicKeyParameters params;
+
+ public BCSphincs256PublicKey(
+ ASN1ObjectIdentifier treeDigest,
+ SPHINCSPublicKeyParameters params)
+ {
+ this.treeDigest = treeDigest;
+ this.params = params;
+ }
+
+ public BCSphincs256PublicKey(SubjectPublicKeyInfo keyInfo)
+ {
+ this.treeDigest = SPHINCS256KeyParams.getInstance(keyInfo.getAlgorithm().getParameters()).getTreeDigest().getAlgorithm();
+ this.params = new SPHINCSPublicKeyParameters(keyInfo.getPublicKeyData().getBytes());
+ }
+
+ /**
+ * Compare this SPHINCS-256 public key with another object.
+ *
+ * @param o the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof BCSphincs256PublicKey))
+ {
+ return false;
+ }
+ BCSphincs256PublicKey otherKey = (BCSphincs256PublicKey)o;
+
+ return treeDigest.equals(otherKey.treeDigest) && Arrays.areEqual(params.getKeyData(), otherKey.params.getKeyData());
+ }
+
+ public int hashCode()
+ {
+ return treeDigest.hashCode() + 37 * Arrays.hashCode(params.getKeyData());
+ }
+
+ /**
+ * @return name of the algorithm - "SPHINCS-256"
+ */
+ public final String getAlgorithm()
+ {
+ return "SPHINCS-256";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest)));
+ pki = new SubjectPublicKeyInfo(algorithmIdentifier, params.getKeyData());
+
+ return pki.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getKeyData()
+ {
+ return params.getKeyData();
+ }
+
+ CipherParameters getKeyParams()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java
new file mode 100644
index 00000000..8d1ef94b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java
@@ -0,0 +1,153 @@
+package org.bouncycastle.pqc.jcajce.provider.sphincs;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHA512tDigest;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256Signer;
+
+public class SignatureSpi
+ extends java.security.SignatureSpi
+{
+ private Digest digest;
+ private SPHINCS256Signer signer;
+ private SecureRandom random;
+
+ protected SignatureSpi(Digest digest, SPHINCS256Signer signer)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (publicKey instanceof BCSphincs256PublicKey)
+ {
+ CipherParameters param = ((BCSphincs256PublicKey)publicKey).getKeyParams();
+
+ digest.reset();
+ signer.init(false, param);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown public key passed to SPHINCS-256");
+ }
+ }
+
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (privateKey instanceof BCSphincs256PrivateKey)
+ {
+ CipherParameters param = ((BCSphincs256PrivateKey)privateKey).getKeyParams();
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown private key passed to SPHINCS-256");
+ }
+ }
+
+ protected void engineUpdate(byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ try
+ {
+ byte[] sig = signer.generateSignature(hash);
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ return signer.verifySignature(hash, sigBytes);
+ }
+
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ {
+ // TODO
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href =
+ * "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"
+ * >
+ */
+ protected void engineSetParameter(String param, Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ static public class withSha512
+ extends SignatureSpi
+ {
+ public withSha512()
+ {
+ super(new SHA512Digest(), new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest()));
+ }
+ }
+
+ static public class withSha3_512
+ extends SignatureSpi
+ {
+ public withSha3_512()
+ {
+ super(new SHA3Digest(512), new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512)));
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyFactorySpi.java
new file mode 100644
index 00000000..8a371f70
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyFactorySpi.java
@@ -0,0 +1,116 @@
+package org.bouncycastle.pqc.jcajce.provider.sphincs;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class Sphincs256KeyFactorySpi
+ extends KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ public PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ public PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
+ }
+
+ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCSphincs256PrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else if (key instanceof BCSphincs256PublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ public final Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCSphincs256PrivateKey || key instanceof BCSphincs256PublicKey)
+ {
+ return key;
+ }
+
+ throw new InvalidKeyException("Unsupported key type");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCSphincs256PrivateKey(keyInfo);
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ return new BCSphincs256PublicKey(keyInfo);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyPairGeneratorSpi.java
new file mode 100644
index 00000000..e05b04a6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincs/Sphincs256KeyPairGeneratorSpi.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.pqc.jcajce.provider.sphincs;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.digests.SHA3Digest;
+import org.bouncycastle.crypto.digests.SHA512tDigest;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyPairGenerator;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec;
+
+public class Sphincs256KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ ASN1ObjectIdentifier treeDigest = NISTObjectIdentifiers.id_sha512_256;
+
+ SPHINCS256KeyGenerationParameters param;
+ SPHINCS256KeyPairGenerator engine = new SPHINCS256KeyPairGenerator();
+
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public Sphincs256KeyPairGeneratorSpi()
+ {
+ super("SPHINCS256");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ throw new IllegalArgumentException("use AlgorithmParameterSpec");
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof SPHINCS256KeyGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a SPHINCS256KeyGenParameterSpec");
+ }
+
+ SPHINCS256KeyGenParameterSpec sphincsParams = (SPHINCS256KeyGenParameterSpec)params;
+
+ if (sphincsParams.getTreeDigest().equals(SPHINCS256KeyGenParameterSpec.SHA512_256))
+ {
+ treeDigest = NISTObjectIdentifiers.id_sha512_256;
+ param = new SPHINCS256KeyGenerationParameters(random, new SHA512tDigest(256));
+ }
+ else if (sphincsParams.getTreeDigest().equals(SPHINCS256KeyGenParameterSpec.SHA3_256))
+ {
+ treeDigest = NISTObjectIdentifiers.id_sha3_256;
+ param = new SPHINCS256KeyGenerationParameters(random, new SHA3Digest(256));
+ }
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ param = new SPHINCS256KeyGenerationParameters(random, new SHA512tDigest(256));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)pair.getPublic();
+ SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCSphincs256PublicKey(treeDigest, pub), new BCSphincs256PrivateKey(treeDigest, priv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
index 902d9063..4b2592f0 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java
@@ -24,12 +24,19 @@ public class AllTests
{
Security.addProvider(new BouncyCastlePQCProvider());
}
-
+
+ suite.addTestSuite(Sphincs256Test.class);
suite.addTestSuite(RainbowSignatureTest.class);
suite.addTestSuite(McElieceFujisakiCipherTest.class);
suite.addTestSuite(McElieceKobaraImaiCipherTest.class);
suite.addTestSuite(McEliecePointchevalCipherTest.class);
- suite.addTestSuite(McEliecePKCSCipherTest.class);
+ suite.addTestSuite(McElieceCipherTest.class);
+ suite.addTestSuite(McElieceKeyPairGeneratorTest.class);
+ suite.addTestSuite(McElieceCCA2KeyPairGeneratorTest.class);
+ suite.addTestSuite(NewHopeTest.class);
+ suite.addTestSuite(NewHopeKeyPairGeneratorTest.class);
+ suite.addTestSuite(Sphincs256Test.class);
+ suite.addTestSuite(Sphincs256KeyPairGeneratorTest.class);
return new BCTestSetup(suite);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/KeyPairGeneratorTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/KeyPairGeneratorTest.java
index f1da055c..424acaa3 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/KeyPairGeneratorTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/KeyPairGeneratorTest.java
@@ -16,11 +16,10 @@ public abstract class KeyPairGeneratorTest
protected KeyFactory kf;
- protected final void performKeyPairEncodingTest()
+ protected final void performKeyPairEncodingTest(KeyPair keyPair)
{
try
- {
- KeyPair keyPair = kpg.genKeyPair();
+ {;
PublicKey pubKey = keyPair.getPublic();
PrivateKey privKey = keyPair.getPrivate();
@@ -28,8 +27,7 @@ public abstract class KeyPairGeneratorTest
byte[] encPrivKey = privKey.getEncoded();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encPubKey);
- PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
- encPrivKey);
+ PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encPrivKey);
PublicKey decPubKey = kf.generatePublic(pubKeySpec);
PrivateKey decPrivKey = kf.generatePrivate(privKeySpec);
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java
index ccb06ae9..ecb06bee 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java
@@ -2,9 +2,9 @@ package org.bouncycastle.pqc.jcajce.provider.test;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
public class McElieceCCA2KeyPairGeneratorTest
@@ -14,24 +14,25 @@ public class McElieceCCA2KeyPairGeneratorTest
protected void setUp()
{
super.setUp();
- try
- {
- kf = KeyFactory.getInstance("McElieceCCA2");
- }
- catch (NoSuchAlgorithmException e)
- {
- e.printStackTrace();
- }
}
+ public void testKeyFactory()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("McElieceKobaraImai");
+ kf = KeyFactory.getInstance("McEliecePointcheval");
+ kf = KeyFactory.getInstance("McElieceFujisaki");
+ kf = KeyFactory.getInstance(PQCObjectIdentifiers.mcElieceCca2.getId());
+ }
public void testKeyPairEncoding_9_33()
throws Exception
{
+ kf = KeyFactory.getInstance(PQCObjectIdentifiers.mcElieceCca2.getId());
+
kpg = KeyPairGenerator.getInstance("McElieceKobaraImai");
- ECCKeyGenParameterSpec params = new ECCKeyGenParameterSpec(9, 33);
+ McElieceCCA2KeyGenParameterSpec params = new McElieceCCA2KeyGenParameterSpec(9, 33);
kpg.initialize(params);
- performKeyPairEncodingTest();
+ performKeyPairEncodingTest(kpg.generateKeyPair());
}
-
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java
index 39e16ad2..f3ffeb84 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java
@@ -7,7 +7,7 @@ import java.security.NoSuchAlgorithmException;
import org.bouncycastle.pqc.jcajce.provider.mceliece.BCMcElieceCCA2PrivateKey;
import org.bouncycastle.pqc.jcajce.provider.mceliece.BCMcElieceCCA2PublicKey;
import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceCCA2Primitives;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec;
import org.bouncycastle.pqc.math.linearalgebra.GF2Vector;
@@ -64,7 +64,7 @@ public class McElieceCCA2PrimitivesTest
private void initKPG(int m, int t)
throws Exception
{
- ECCKeyGenParameterSpec params = new ECCKeyGenParameterSpec(m, t);
+ McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(m, t);
kpg.initialize(params);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePKCSCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java
index 74ab66b7..9e6f7ba4 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePKCSCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java
@@ -4,9 +4,9 @@ import java.security.KeyPairGenerator;
import javax.crypto.Cipher;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec;
-public class McEliecePKCSCipherTest
+public class McElieceCipherTest
extends AsymmetricBlockCipherTest
{
@@ -16,8 +16,8 @@ public class McEliecePKCSCipherTest
try
{
- kpg = KeyPairGenerator.getInstance("McEliecePKCS");
- cipher = Cipher.getInstance("McEliecePKCSwithSHA256");
+ kpg = KeyPairGenerator.getInstance("McEliece");
+ cipher = Cipher.getInstance("McEliece");
}
catch (Exception e)
{
@@ -30,7 +30,7 @@ public class McEliecePKCSCipherTest
public void testEnDecryption_9_33()
throws Exception
{
- ECCKeyGenParameterSpec params = new ECCKeyGenParameterSpec(9, 33);
+ McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33);
kpg.initialize(params);
performEnDecryptionTest(2, 10, params);
}
@@ -38,7 +38,7 @@ public class McEliecePKCSCipherTest
public void testEnDecryption_11_50()
throws Exception
{
- ECCKeyGenParameterSpec params = new ECCKeyGenParameterSpec(11, 50);
+ McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(11, 50);
kpg.initialize(params);
performEnDecryptionTest(2, 10, params);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java
index 2f793a64..671dbbf7 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java
@@ -4,7 +4,7 @@ import java.security.KeyPairGenerator;
import javax.crypto.Cipher;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
public class McElieceFujisakiCipherTest
@@ -17,7 +17,7 @@ public class McElieceFujisakiCipherTest
try
{
kpg = KeyPairGenerator.getInstance("McElieceFujisaki");
- cipher = Cipher.getInstance("McElieceFujisakiWithSHA256");
+ cipher = Cipher.getInstance("McElieceFujisaki");
}
catch (Exception e)
{
@@ -30,15 +30,37 @@ public class McElieceFujisakiCipherTest
* Test encryption and decryption performance for SHA256 message digest and parameters
* m=11, t=50.
*/
- public void testEnDecryption_SHA256_11_50()
+
+ public void testEnDecryption_SHA1_11_50()
+ throws Exception
+ {
+ // initialize key pair generator
+ McElieceCCA2KeyGenParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50, McElieceCCA2KeyGenParameterSpec.SHA1);
+ kpg.initialize(kpgParams);
+
+ // perform test
+ performEnDecryptionTest(1, 10, 32, null);
+ }
+
+ public void testEnDecryption_SHA224_11_50()
throws Exception
{
// initialize key pair generator
- ECCKeyGenParameterSpec kpgParams = new ECCKeyGenParameterSpec(11, 50);
+ McElieceCCA2KeyGenParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50, McElieceCCA2KeyGenParameterSpec.SHA224);
kpg.initialize(kpgParams);
// perform test
performEnDecryptionTest(1, 10, 32, null);
}
+ public void testEnDecryption_SHA256_11_50()
+ throws Exception
+ {
+ // initialize key pair generator
+ McElieceCCA2KeyGenParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50, McElieceCCA2KeyGenParameterSpec.SHA256);
+ kpg.initialize(kpgParams);
+
+ // perform test
+ performEnDecryptionTest(1, 10, 32, null);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java
index 5c68fdea..a8326bc3 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java
@@ -2,9 +2,9 @@ package org.bouncycastle.pqc.jcajce.provider.test;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec;
public class McElieceKeyPairGeneratorTest
@@ -14,23 +14,24 @@ public class McElieceKeyPairGeneratorTest
protected void setUp()
{
super.setUp();
- try
- {
- kf = KeyFactory.getInstance("McEliece");
- }
- catch (NoSuchAlgorithmException e)
- {
- e.printStackTrace();
- }
+ }
+
+ public void testKeyFactory()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("McEliece");
+ kf = KeyFactory.getInstance(PQCObjectIdentifiers.mcEliece.getId());
}
public void testKeyPairEncoding_9_33()
throws Exception
{
- kpg = KeyPairGenerator.getInstance("McEliecePKCS");
- ECCKeyGenParameterSpec params = new ECCKeyGenParameterSpec(9, 33);
+ kf = KeyFactory.getInstance("McEliece");
+
+ kpg = KeyPairGenerator.getInstance("McEliece");
+ McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33);
kpg.initialize(params);
- performKeyPairEncodingTest();
+ performKeyPairEncodingTest(kpg.generateKeyPair());
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java
index 8a9746f2..944b62c1 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java
@@ -5,7 +5,7 @@ import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
public class McElieceKobaraImaiCipherTest
@@ -18,7 +18,7 @@ public class McElieceKobaraImaiCipherTest
try
{
kpg = KeyPairGenerator.getInstance("McElieceKobaraImai");
- cipher = Cipher.getInstance("McElieceKobaraImaiWithSHA256");
+ cipher = Cipher.getInstance("McElieceKobaraImai");
}
catch (Exception e)
{
@@ -34,7 +34,7 @@ public class McElieceKobaraImaiCipherTest
throws Exception
{
// initialize key pair generator
- AlgorithmParameterSpec kpgParams = new ECCKeyGenParameterSpec(11, 50);
+ AlgorithmParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50);
kpg.initialize(kpgParams);
performEnDecryptionTest(0, 10, 32, null); // TODO: McElieceKobaraImai is broken
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java
index 791baa1d..d1af36ee 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java
@@ -5,7 +5,7 @@ import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
-import org.bouncycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
public class McEliecePointchevalCipherTest
extends AsymmetricHybridCipherTest
@@ -17,7 +17,7 @@ public class McEliecePointchevalCipherTest
try
{
kpg = KeyPairGenerator.getInstance("McEliecePointcheval");
- cipher = Cipher.getInstance("McEliecePointchevalWithSHA256");
+ cipher = Cipher.getInstance("McEliecePointcheval");
}
catch (Exception e)
{
@@ -33,7 +33,7 @@ public class McEliecePointchevalCipherTest
throws Exception
{
// initialize key pair generator
- AlgorithmParameterSpec kpgParams = new ECCKeyGenParameterSpec(11, 50);
+ AlgorithmParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50);
kpg.initialize(kpgParams);
// perform test
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java
new file mode 100644
index 00000000..07d07b78
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeKeyPairGeneratorTest.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+
+
+public class NewHopeKeyPairGeneratorTest
+ extends KeyPairGeneratorTest
+{
+
+ protected void setUp()
+ {
+ super.setUp();
+ }
+
+ public void testKeyFactory()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("NH", "BCPQC");
+ kf = KeyFactory.getInstance(PQCObjectIdentifiers.newHope.getId(), "BCPQC");
+ }
+
+ public void testKeyPairEncoding()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("NH", "BCPQC");
+
+ kpg = KeyPairGenerator.getInstance("NH", "BCPQC");
+ kpg.initialize(1024, new SecureRandom());
+
+ performKeyPairEncodingTest(kpg.generateKeyPair());
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java
new file mode 100644
index 00000000..3eeae4f1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/NewHopeTest.java
@@ -0,0 +1,59 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import javax.crypto.KeyAgreement;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.util.Arrays;
+
+public class NewHopeTest
+ extends TestCase
+{
+ public void setUp()
+ {
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ public void testKeyExchange()
+ throws Exception
+ {
+ SecureRandom aliceRand = new SecureRandom();
+ SecureRandom bobRand = new SecureRandom();
+
+ for (int i = 0; i < 1000; ++i)
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("NH", "BCPQC");
+
+ kpGen.initialize(1024, aliceRand);
+
+ KeyPair aliceKp = kpGen.generateKeyPair();
+
+ KeyAgreement bobAgree = KeyAgreement.getInstance("NH", "BCPQC");
+
+ // responder has no private key, but needs a random number source.
+ bobAgree.init(null, bobRand);
+
+ Key bobSend = bobAgree.doPhase(aliceKp.getPublic(), true);
+
+ KeyAgreement aliceAgree = KeyAgreement.getInstance("NH", "BCPQC");
+
+ // initiator uses both private key
+ aliceAgree.init(aliceKp.getPrivate());
+
+ // and recipient's public key.
+ aliceAgree.doPhase(bobSend, true);
+
+ Assert.assertTrue("value mismatch", Arrays.areEqual(aliceAgree.generateSecret(), bobAgree.generateSecret()));
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java
index 69f69b62..e8a2a333 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowSignatureTest.java
@@ -92,7 +92,7 @@ public class RainbowSignatureTest
{
// generate new signature instance for verification
// sigVerify = (Signature) sig.getClass().newInstance();
- sigVerify = Signature.getInstance("SHA384WITHRainbow");
+ sigVerify = Signature.getInstance("SHA384withRainbow", "BCPQC");
for (int j = 0; j < numPassesKPG; j++)
{
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java
new file mode 100644
index 00000000..7524dbc2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256KeyPairGeneratorTest.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+
+import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec;
+
+
+public class Sphincs256KeyPairGeneratorTest
+ extends KeyPairGeneratorTest
+{
+
+ protected void setUp()
+ {
+ super.setUp();
+ }
+
+ public void testKeyFactory()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("SPHINCS256", "BCPQC");
+ kf = KeyFactory.getInstance(PQCObjectIdentifiers.newHope.getId(), "BCPQC");
+ }
+
+ public void testKeyPairEncoding()
+ throws Exception
+ {
+ kf = KeyFactory.getInstance("SPHINCS256", "BCPQC");
+
+ kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), new SecureRandom());
+ performKeyPairEncodingTest(kpg.generateKeyPair());
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256Test.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256Test.java
new file mode 100644
index 00000000..bd31ea3f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/provider/test/Sphincs256Test.java
@@ -0,0 +1,1158 @@
+package org.bouncycastle.pqc.jcajce.provider.test;
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import org.bouncycastle.pqc.jcajce.interfaces.SPHINCSKey;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Base64;
+
+public class Sphincs256Test
+ extends TestCase
+{
+ // test vector courtesy the "Yawning Angel" GO implementation and the SUPERCOP reference implementation.
+ byte[] msg = Strings.toByteArray("Cthulhu Fthagn --What a wonderful phrase!Cthulhu Fthagn --Say it and you're crazed!");
+
+ byte[] expSha2Pub = Base64.decode(
+ "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+ + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+ + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+ + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+ + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+ + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+ + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+ + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+ + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+ + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+ + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+ + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH6oCyxVnw+pTAdU/b4PWLQU4M29Fe8TFHP+s9whN/N+Y");
+
+ byte[] expSha2Priv = Base64.decode(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+ + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+ + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+ + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+ + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+ + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+ + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+ + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+ + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+ + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+ + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+ + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+ + "ODk6Ozw9Pj8=");
+
+ // note this is different from the light weight one as a hash is applied to actual message before processing.
+ byte[] expSha2Sig = Base64.decode(
+ "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");
+
+ byte[] expSha3Pub = Base64.decode(
+ "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+ + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+ + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+ + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+ + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+ + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+ + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+ + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+ + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+ + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+ + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+ + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHzzFqLKvvsdZOxldDTvCy40RGXZFsOAMP1jw0XlUMqq9");
+
+ byte[] expSha3Priv = Base64.decode(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+ + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+ + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+ + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+ + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+ + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+ + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+ + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+ + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+ + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+ + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+ + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+ + "ODk6Ozw9Pj8=");
+
+ // note this is different from the light weight one as a hash is applied to actual message before processing.
+ byte[] expSha3Sig = Base64.decode(
+ "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");
+
+ public void setUp()
+ {
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ public void testSphincsDefaultKeyGen()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(), new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ SPHINCSKey pub = (SPHINCSKey)kp.getPublic();
+
+ assertTrue(Arrays.areEqual(expSha2Pub, pub.getKeyData()));
+
+ SPHINCSKey priv = (SPHINCSKey)kp.getPrivate();
+
+ assertTrue(Arrays.areEqual(expSha2Priv, priv.getKeyData()));
+
+ KeyFactory keyFact = KeyFactory.getInstance("SPHINCS256", "BCPQC");
+
+ SPHINCSKey pub2 = (SPHINCSKey)keyFact.generatePublic(new X509EncodedKeySpec(pub.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha2Pub, pub2.getKeyData()));
+
+ SPHINCSKey priv2 = (SPHINCSKey)keyFact.generatePrivate(new PKCS8EncodedKeySpec(priv.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha2Priv, priv2.getKeyData()));
+ }
+
+ public void testSphincsDefaultSha2KeyGen()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ SPHINCSKey pub = (SPHINCSKey)kp.getPublic();
+
+ assertTrue(Arrays.areEqual(expSha2Pub, pub.getKeyData()));
+
+ SPHINCSKey priv = (SPHINCSKey)kp.getPrivate();
+
+ assertTrue(Arrays.areEqual(expSha2Priv, priv.getKeyData()));
+
+ KeyFactory keyFact = KeyFactory.getInstance("SPHINCS256", "BCPQC");
+
+ SPHINCSKey pub2 = (SPHINCSKey)keyFact.generatePublic(new X509EncodedKeySpec(pub.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha2Pub, pub2.getKeyData()));
+
+ SubjectPublicKeyInfo pkInfo = SubjectPublicKeyInfo.getInstance(pub2.getEncoded());
+
+ assertEquals(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256), SPHINCS256KeyParams.getInstance(pkInfo.getAlgorithm().getParameters()).getTreeDigest());
+
+ SPHINCSKey priv2 = (SPHINCSKey)keyFact.generatePrivate(new PKCS8EncodedKeySpec(priv.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha2Priv, priv2.getKeyData()));
+ }
+
+ public void testSphincsDefaultSha3KeyGen()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA3_256), new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ SPHINCSKey pub = (SPHINCSKey)kp.getPublic();
+
+ assertTrue(Arrays.areEqual(expSha3Pub, pub.getKeyData()));
+
+ SPHINCSKey priv = (SPHINCSKey)kp.getPrivate();
+
+ assertTrue(Arrays.areEqual(expSha3Priv, priv.getKeyData()));
+
+ KeyFactory keyFact = KeyFactory.getInstance("SPHINCS256", "BCPQC");
+
+ SPHINCSKey pub2 = (SPHINCSKey)keyFact.generatePublic(new X509EncodedKeySpec(pub.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha3Pub, pub2.getKeyData()));
+
+ SubjectPublicKeyInfo pkInfo = SubjectPublicKeyInfo.getInstance(pub2.getEncoded());
+
+ assertEquals(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha3_256), SPHINCS256KeyParams.getInstance(pkInfo.getAlgorithm().getParameters()).getTreeDigest());
+
+ SPHINCSKey priv2 = (SPHINCSKey)keyFact.generatePrivate(new PKCS8EncodedKeySpec(priv.getEncoded()));
+
+ assertTrue(Arrays.areEqual(expSha3Priv, priv2.getKeyData()));
+ }
+
+ public void testSphincsSha2Signature()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ Signature sig = Signature.getInstance("SHA512withSPHINCS256", "BCPQC");
+
+ sig.initSign(kp.getPrivate());
+
+ sig.update(msg, 0, msg.length);
+
+ byte[] s = sig.sign();
+
+ assertTrue(Arrays.areEqual(expSha2Sig, s));
+ }
+
+ public void testSphincsSha3Signature()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
+
+ kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256), new RiggedRandom());
+
+ KeyPair kp = kpg.generateKeyPair();
+
+ Signature sig = Signature.getInstance("SHA3-512withSPHINCS256", "BCPQC");
+
+ sig.initSign(kp.getPrivate());
+
+ sig.update(msg, 0, msg.length);
+
+ byte[] s = sig.sign();
+
+ assertTrue(Arrays.areEqual(expSha3Sig, s));
+ }
+
+ private static class RiggedRandom
+ extends SecureRandom
+ {
+ public void nextBytes(byte[] bytes)
+ {
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(i & 0xff);
+ }
+ }
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSKeySpec.java
deleted file mode 100644
index 7e469f0e..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSKeySpec.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-import java.security.spec.KeySpec;
-
-import org.bouncycastle.pqc.crypto.gmss.GMSSParameters;
-
-public class GMSSKeySpec
- implements KeySpec
-{
- /**
- * The GMSSParameterSet
- */
- private GMSSParameters gmssParameterSet;
-
- protected GMSSKeySpec(GMSSParameters gmssParameterSet)
- {
- this.gmssParameterSet = gmssParameterSet;
- }
-
- /**
- * Returns the GMSS parameter set
- *
- * @return The GMSS parameter set
- */
- public GMSSParameters getParameters()
- {
- return gmssParameterSet;
- }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java
deleted file mode 100644
index 150e9dc5..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java
+++ /dev/null
@@ -1,353 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-import java.security.spec.KeySpec;
-import java.util.Vector;
-
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.pqc.crypto.gmss.GMSSLeaf;
-import org.bouncycastle.pqc.crypto.gmss.GMSSParameters;
-import org.bouncycastle.pqc.crypto.gmss.GMSSRootCalc;
-import org.bouncycastle.pqc.crypto.gmss.GMSSRootSig;
-import org.bouncycastle.pqc.crypto.gmss.Treehash;
-import org.bouncycastle.util.Arrays;
-
-
-/**
- * This class provides a specification for a GMSS private key.
- */
-public class GMSSPrivateKeySpec
- implements KeySpec
-{
-
- private int[] index;
-
- private byte[][] currentSeed;
- private byte[][] nextNextSeed;
-
- private byte[][][] currentAuthPath;
- private byte[][][] nextAuthPath;
-
- private Treehash[][] currentTreehash;
- private Treehash[][] nextTreehash;
-
- private Vector[] currentStack;
- private Vector[] nextStack;
-
- private Vector[][] currentRetain;
- private Vector[][] nextRetain;
-
- private byte[][][] keep;
-
- private GMSSLeaf[] nextNextLeaf;
- private GMSSLeaf[] upperLeaf;
- private GMSSLeaf[] upperTreehashLeaf;
-
- private int[] minTreehash;
-
- private GMSSParameters gmssPS;
-
- private byte[][] nextRoot;
- private GMSSRootCalc[] nextNextRoot;
-
- private byte[][] currentRootSig;
- private GMSSRootSig[] nextRootSig;
-
- /**
- * @param index tree indices
- * @param currentSeed seed for the generation of private OTS keys for the
- * current subtrees (TREE)
- * @param nextNextSeed seed for the generation of private OTS keys for the
- * subtrees after next (TREE++)
- * @param currentAuthPath array of current authentication paths (AUTHPATH)
- * @param nextAuthPath array of next authentication paths (AUTHPATH+)
- * @param keep keep array for the authPath algorithm
- * @param currentTreehash treehash for authPath algorithm of current tree
- * @param nextTreehash treehash for authPath algorithm of next tree (TREE+)
- * @param currentStack shared stack for authPath algorithm of current tree
- * @param nextStack shared stack for authPath algorithm of next tree (TREE+)
- * @param currentRetain retain stack for authPath algorithm of current tree
- * @param nextRetain retain stack for authPath algorithm of next tree (TREE+)
- * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of
- * each layer
- * @param upperLeaf needed for precomputation of upper nodes
- * @param upperTreehashLeaf needed for precomputation of upper treehash nodes
- * @param minTreehash index of next treehash instance to receive an update
- * @param nextRoot the roots of the next trees (ROOT+)
- * @param nextNextRoot the roots of the tree after next (ROOT++)
- * @param currentRootSig array of signatures of the roots of the current subtrees
- * (SIG)
- * @param nextRootSig array of signatures of the roots of the next subtree
- * (SIG+)
- * @param gmssParameterset the GMSS Parameterset
- */
- public GMSSPrivateKeySpec(int[] index, byte[][] currentSeed,
- byte[][] nextNextSeed, byte[][][] currentAuthPath,
- byte[][][] nextAuthPath, Treehash[][] currentTreehash,
- Treehash[][] nextTreehash, Vector[] currentStack,
- Vector[] nextStack, Vector[][] currentRetain,
- Vector[][] nextRetain, byte[][][] keep, GMSSLeaf[] nextNextLeaf,
- GMSSLeaf[] upperLeaf, GMSSLeaf[] upperTreehashLeaf,
- int[] minTreehash, byte[][] nextRoot, GMSSRootCalc[] nextNextRoot,
- byte[][] currentRootSig, GMSSRootSig[] nextRootSig,
- GMSSParameters gmssParameterset)
- {
- this.index = index;
- this.currentSeed = currentSeed;
- this.nextNextSeed = nextNextSeed;
- this.currentAuthPath = currentAuthPath;
- this.nextAuthPath = nextAuthPath;
- this.currentTreehash = currentTreehash;
- this.nextTreehash = nextTreehash;
- this.currentStack = currentStack;
- this.nextStack = nextStack;
- this.currentRetain = currentRetain;
- this.nextRetain = nextRetain;
- this.keep = keep;
- this.nextNextLeaf = nextNextLeaf;
- this.upperLeaf = upperLeaf;
- this.upperTreehashLeaf = upperTreehashLeaf;
- this.minTreehash = minTreehash;
- this.nextRoot = nextRoot;
- this.nextNextRoot = nextNextRoot;
- this.currentRootSig = currentRootSig;
- this.nextRootSig = nextRootSig;
- this.gmssPS = gmssParameterset;
- }
-
- public int[] getIndex()
- {
- return Arrays.clone(index);
- }
-
- public byte[][] getCurrentSeed()
- {
- return clone(currentSeed);
- }
-
- public byte[][] getNextNextSeed()
- {
- return clone(nextNextSeed);
- }
-
- public byte[][][] getCurrentAuthPath()
- {
- return clone(currentAuthPath);
- }
-
- public byte[][][] getNextAuthPath()
- {
- return clone(nextAuthPath);
- }
-
- public Treehash[][] getCurrentTreehash()
- {
- return clone(currentTreehash);
- }
-
- public Treehash[][] getNextTreehash()
- {
- return clone(nextTreehash);
- }
-
- public byte[][][] getKeep()
- {
- return clone(keep);
- }
-
- public Vector[] getCurrentStack()
- {
- return clone(currentStack);
- }
-
- public Vector[] getNextStack()
- {
- return clone(nextStack);
- }
-
- public Vector[][] getCurrentRetain()
- {
- return clone(currentRetain);
- }
-
- public Vector[][] getNextRetain()
- {
- return clone(nextRetain);
- }
-
- public GMSSLeaf[] getNextNextLeaf()
- {
- return clone(nextNextLeaf);
- }
-
- public GMSSLeaf[] getUpperLeaf()
- {
- return clone(upperLeaf);
- }
-
- public GMSSLeaf[] getUpperTreehashLeaf()
- {
- return clone(upperTreehashLeaf);
- }
-
- public int[] getMinTreehash()
- {
- return Arrays.clone(minTreehash);
- }
-
- public GMSSRootSig[] getNextRootSig()
- {
- return clone(nextRootSig);
- }
-
- public GMSSParameters getGmssPS()
- {
- return gmssPS;
- }
-
- public byte[][] getNextRoot()
- {
- return clone(nextRoot);
- }
-
- public GMSSRootCalc[] getNextNextRoot()
- {
- return clone(nextNextRoot);
- }
-
- public byte[][] getCurrentRootSig()
- {
- return clone(currentRootSig);
- }
-
- private static GMSSLeaf[] clone(GMSSLeaf[] data)
- {
- if (data == null)
- {
- return null;
- }
- GMSSLeaf[] copy = new GMSSLeaf[data.length];
-
- System.arraycopy(data, 0, copy, 0, data.length);
-
- return copy;
- }
-
- private static GMSSRootCalc[] clone(GMSSRootCalc[] data)
- {
- if (data == null)
- {
- return null;
- }
- GMSSRootCalc[] copy = new GMSSRootCalc[data.length];
-
- System.arraycopy(data, 0, copy, 0, data.length);
-
- return copy;
- }
-
- private static GMSSRootSig[] clone(GMSSRootSig[] data)
- {
- if (data == null)
- {
- return null;
- }
- GMSSRootSig[] copy = new GMSSRootSig[data.length];
-
- System.arraycopy(data, 0, copy, 0, data.length);
-
- return copy;
- }
-
- private static byte[][] clone(byte[][] data)
- {
- if (data == null)
- {
- return null;
- }
- byte[][] copy = new byte[data.length][];
-
- for (int i = 0; i != data.length; i++)
- {
- copy[i] = Arrays.clone(data[i]);
- }
-
- return copy;
- }
-
- private static byte[][][] clone(byte[][][] data)
- {
- if (data == null)
- {
- return null;
- }
- byte[][][] copy = new byte[data.length][][];
-
- for (int i = 0; i != data.length; i++)
- {
- copy[i] = clone(data[i]);
- }
-
- return copy;
- }
-
- private static Treehash[] clone(Treehash[] data)
- {
- if (data == null)
- {
- return null;
- }
- Treehash[] copy = new Treehash[data.length];
-
- System.arraycopy(data, 0, copy, 0, data.length);
-
- return copy;
- }
-
- private static Treehash[][] clone(Treehash[][] data)
- {
- if (data == null)
- {
- return null;
- }
- Treehash[][] copy = new Treehash[data.length][];
-
- for (int i = 0; i != data.length; i++)
- {
- copy[i] = clone(data[i]);
- }
-
- return copy;
- }
-
- private static Vector[] clone(Vector[] data)
- {
- if (data == null)
- {
- return null;
- }
- Vector[] copy = new Vector[data.length];
-
- for (int i = 0; i != data.length; i++)
- {
- copy[i] = new Vector(data[i]);
- }
-
- return copy;
- }
-
- private static Vector[][] clone(Vector[][] data)
- {
- if (data == null)
- {
- return null;
- }
- Vector[][] copy = new Vector[data.length][];
-
- for (int i = 0; i != data.length; i++)
- {
- copy[i] = clone(data[i]);
- }
-
- return copy;
- }
-} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java
deleted file mode 100644
index 441febd6..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-import org.bouncycastle.pqc.crypto.gmss.GMSSParameters;
-
-/**
- * This class provides a specification for a GMSS public key.
- *
- * @see org.bouncycastle.pqc.jcajce.provider.gmss.BCGMSSPublicKey
- */
-public class GMSSPublicKeySpec
- extends GMSSKeySpec
-{
- /**
- * The GMSS public key
- */
- private byte[] gmssPublicKey;
-
- /**
- * The constructor.
- *
- * @param key a raw GMSS public key
- * @param gmssParameterSet an instance of GMSSParameterSet
- */
- public GMSSPublicKeySpec(byte[] key, GMSSParameters gmssParameterSet)
- {
- super(gmssParameterSet);
-
- this.gmssPublicKey = key;
- }
-
- /**
- * Returns the GMSS public key
- *
- * @return The GMSS public key
- */
- public byte[] getPublicKey()
- {
- return gmssPublicKey;
- }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java
new file mode 100644
index 00000000..9b41ac64
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java
@@ -0,0 +1,219 @@
+package org.bouncycastle.pqc.jcajce.spec;
+
+import java.security.InvalidParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2;
+
+/**
+ * This class provides a specification for the parameters that are used by the
+ * McEliece, McElieceCCA2, and Niederreiter key pair generators.
+ */
+public class McElieceCCA2KeyGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+ public static final String SHA1 = "SHA-1";
+ public static final String SHA224 = "SHA-224";
+ public static final String SHA256 = "SHA-256";
+ public static final String SHA384 = "SHA-384";
+ public static final String SHA512 = "SHA-512";
+
+ /**
+ * The default extension degree
+ */
+ public static final int DEFAULT_M = 11;
+
+ /**
+ * The default error correcting capability.
+ */
+ public static final int DEFAULT_T = 50;
+
+ /**
+ * extension degree of the finite field GF(2^m)
+ */
+ private final int m;
+
+ /**
+ * error correction capability of the code
+ */
+ private final int t;
+
+ /**
+ * length of the code
+ */
+ private final int n;
+
+ /**
+ * the field polynomial
+ */
+ private int fieldPoly;
+
+ private final String digest;
+
+ /**
+ * Constructor. Set the default parameters: extension degree.
+ */
+ public McElieceCCA2KeyGenParameterSpec()
+ {
+ this(DEFAULT_M, DEFAULT_T, SHA256);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
+ */
+ public McElieceCCA2KeyGenParameterSpec(int keysize)
+ {
+ this(keysize, SHA256);
+ }
+
+ public McElieceCCA2KeyGenParameterSpec(int keysize, String digest)
+ {
+ if (keysize < 1)
+ {
+ throw new IllegalArgumentException("key size must be positive");
+ }
+ int m = 0;
+ int n = 1;
+ while (n < keysize)
+ {
+ n <<= 1;
+ m++;
+ }
+ t = (n >>> 1) / m;
+
+ this.m = m;
+ this.n = n;
+ this.fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ this.digest = digest;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws InvalidParameterException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
+ */
+ public McElieceCCA2KeyGenParameterSpec(int m, int t)
+ {
+ this(m, t, SHA256);
+ }
+
+ public McElieceCCA2KeyGenParameterSpec(int m, int t, String digest)
+ {
+ if (m < 1)
+ {
+ throw new IllegalArgumentException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new IllegalArgumentException("m is too large");
+ }
+ this.m = m;
+ n = 1 << m;
+ if (t < 0)
+ {
+ throw new IllegalArgumentException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new IllegalArgumentException("t must be less than n = 2^m");
+ }
+ this.t = t;
+ fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ this.digest = digest;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
+ * <tt>poly</tt> is not an irreducible field polynomial.
+ */
+ public McElieceCCA2KeyGenParameterSpec(int m, int t, int poly)
+ {
+ this(m, t, poly, SHA256);
+ }
+
+ public McElieceCCA2KeyGenParameterSpec(int m, int t, int poly, String digest)
+ {
+ this.m = m;
+ if (m < 1)
+ {
+ throw new IllegalArgumentException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new IllegalArgumentException(" m is too large");
+ }
+ this.n = 1 << m;
+ this.t = t;
+ if (t < 0)
+ {
+ throw new IllegalArgumentException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new IllegalArgumentException("t must be less than n = 2^m");
+ }
+ if ((PolynomialRingGF2.degree(poly) == m)
+ && (PolynomialRingGF2.isIrreducible(poly)))
+ {
+ this.fieldPoly = poly;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "polynomial is not a field polynomial for GF(2^m)");
+ }
+ this.digest = digest;
+ }
+
+ /**
+ * @return the extension degree of the finite field GF(2^m)
+ */
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the field polynomial
+ */
+ public int getFieldPoly()
+ {
+ return fieldPoly;
+ }
+
+ /**
+ * Return CCA-2 digest.
+ */
+ public String getDigest()
+ {
+ return digest;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java
deleted file mode 100644
index 7291f619..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-
-import java.security.spec.AlgorithmParameterSpec;
-
-/**
- * This class provides a specification for the parameters of the CCA2-secure
- * variants of the McEliece PKCS.
- */
-public class McElieceCCA2ParameterSpec
- implements AlgorithmParameterSpec
-{
-
- /**
- * The default message digest ("SHA256").
- */
- public static final String DEFAULT_MD = "SHA256";
-
- private String mdName;
-
- /**
- * Construct the default parameters. Choose the
- */
- public McElieceCCA2ParameterSpec()
- {
- this(DEFAULT_MD);
- }
-
- /**
- * Constructor.
- *
- * @param mdName the name of the hash function
- */
- public McElieceCCA2ParameterSpec(String mdName)
- {
- // check whether message digest is available
- // TODO: this method not used!
-// try {
-// Registry.getMessageDigest(mdName);
-// } catch (NoSuchAlgorithmException nsae) {
-// throw new InvalidParameterException("Message digest '" + mdName
-// + "' not found'.");
-// }
-
- // assign message digest name
- this.mdName = mdName;
- }
-
- /**
- * @return the name of the hash function
- */
- public String getMDName()
- {
- return mdName;
- }
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java
deleted file mode 100644
index a4547cfe..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-import java.security.spec.KeySpec;
-
-import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
-import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
-import org.bouncycastle.pqc.math.linearalgebra.Permutation;
-import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
-
-/**
- * This class provides a specification for a McEliece CCA2 private key.
- */
-public class McElieceCCA2PrivateKeySpec
- implements KeySpec
-{
-
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the dimension of the code
- private int k;
-
- // the finte field GF(2^m)
- private GF2mField field;
-
- // the irreducible Goppa polynomial
- private PolynomialGF2mSmallM goppaPoly;
-
- // the permutation
- private Permutation p;
-
- // the canonical check matrix
- private GF2Matrix h;
-
- // the matrix used to compute square roots in (GF(2^m))^t
- private PolynomialGF2mSmallM[] qInv;
-
- /**
- * Constructor.
- *
- * @param n the length of the code
- * @param k the dimension of the code
- * @param field the finite field <tt>GF(2<sup>m</sup>)</tt>
- * @param gp the irreducible Goppa polynomial
- * @param p the permutation
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2^m))^t</tt>
- */
- public McElieceCCA2PrivateKeySpec(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
- PolynomialGF2mSmallM[] qInv)
- {
- this.oid = oid;
- this.n = n;
- this.k = k;
- this.field = field;
- this.goppaPoly = gp;
- this.p = p;
- this.h = h;
- this.qInv = qInv;
- }
-
- /**
- * Constructor.
- *
- * @param n the length of the code
- * @param k the dimension of the code
- * @param encFieldPoly the encoded field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param encGoppaPoly the encoded irreducible Goppa polynomial
- * @param encP the encoded permutation
- * @param encH the encoded canonical check matrix
- * @param encQInv the encoded matrix used to compute square roots in
- * <tt>(GF(2^m))^t</tt>
- */
- public McElieceCCA2PrivateKeySpec(String oid, int n, int k, byte[] encFieldPoly,
- byte[] encGoppaPoly, byte[] encP, byte[] encH, byte[][] encQInv)
- {
- this.oid = oid;
- this.n = n;
- this.k = k;
- field = new GF2mField(encFieldPoly);
- goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
- p = new Permutation(encP);
- h = new GF2Matrix(encH);
- qInv = new PolynomialGF2mSmallM[encQInv.length];
- for (int i = 0; i < encQInv.length; i++)
- {
- qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
- }
- }
-
- /**
- * @return the length of the code
- */
- public int getN()
- {
- return n;
- }
-
- /**
- * @return the dimension of the code
- */
- public int getK()
- {
- return k;
- }
-
- /**
- * @return the finite field
- */
- public GF2mField getField()
- {
- return field;
- }
-
- /**
- * @return the irreducible Goppa polynomial
- */
- public PolynomialGF2mSmallM getGoppaPoly()
- {
- return goppaPoly;
- }
-
- /**
- * @return the permutation P
- */
- public Permutation getP()
- {
- return p;
- }
-
- /**
- * @return the canonical check matrix H
- */
- public GF2Matrix getH()
- {
- return h;
- }
-
- /**
- * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
- */
- public PolynomialGF2mSmallM[] getQInv()
- {
- return qInv;
- }
-
- public String getOIDString()
- {
- return oid;
-
- }
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java
deleted file mode 100644
index 88a60b99..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-import java.security.spec.KeySpec;
-
-import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
-
-
-/**
- * This class provides a specification for a McEliece CCA2 public key.
- *
- * @see org.bouncycastle.pqc.jcajce.provider.mceliece.BCMcElieceCCA2PublicKey
- */
-public class McElieceCCA2PublicKeySpec
- implements KeySpec
-{
-
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the error correction capability of the code
- private int t;
-
- // the generator matrix
- private GF2Matrix matrixG;
-
- /**
- * Constructor.
- *
- * @param n length of the code
- * @param t error correction capability
- * @param matrix generator matrix
- */
- public McElieceCCA2PublicKeySpec(String oid, int n, int t, GF2Matrix matrix)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.matrixG = new GF2Matrix(matrix);
- }
-
- /**
- * Constructor (used by {@link org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
- *
- * @param n length of the code
- * @param t error correction capability of the code
- * @param encMatrix encoded generator matrix
- */
- public McElieceCCA2PublicKeySpec(String oid, int n, int t, byte[] encMatrix)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.matrixG = new GF2Matrix(encMatrix);
- }
-
- /**
- * @return the length of the code
- */
- public int getN()
- {
- return n;
- }
-
- /**
- * @return the error correction capability of the code
- */
- public int getT()
- {
- return t;
- }
-
- /**
- * @return the generator matrix
- */
- public GF2Matrix getMatrixG()
- {
- return matrixG;
- }
-
- public String getOIDString()
- {
- return oid;
-
- }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java
index 8693eb06..b5bbd23a 100644
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java
@@ -9,7 +9,7 @@ import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2;
* This class provides a specification for the parameters that are used by the
* McEliece, McElieceCCA2, and Niederreiter key pair generators.
*/
-public class ECCKeyGenParameterSpec
+public class McElieceKeyGenParameterSpec
implements AlgorithmParameterSpec
{
@@ -46,7 +46,7 @@ public class ECCKeyGenParameterSpec
/**
* Constructor. Set the default parameters: extension degree.
*/
- public ECCKeyGenParameterSpec()
+ public McElieceKeyGenParameterSpec()
{
this(DEFAULT_M, DEFAULT_T);
}
@@ -55,14 +55,13 @@ public class ECCKeyGenParameterSpec
* Constructor.
*
* @param keysize the length of a Goppa code
- * @throws InvalidParameterException if <tt>keysize &lt; 1</tt>.
+ * @throws IllegalArgumentException if <tt>keysize &lt; 1</tt>.
*/
- public ECCKeyGenParameterSpec(int keysize)
- throws InvalidParameterException
+ public McElieceKeyGenParameterSpec(int keysize)
{
if (keysize < 1)
{
- throw new InvalidParameterException("key size must be positive");
+ throw new IllegalArgumentException("key size must be positive");
}
m = 0;
n = 1;
@@ -84,26 +83,26 @@ public class ECCKeyGenParameterSpec
* @throws InvalidParameterException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
* <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
*/
- public ECCKeyGenParameterSpec(int m, int t)
+ public McElieceKeyGenParameterSpec(int m, int t)
throws InvalidParameterException
{
if (m < 1)
{
- throw new InvalidParameterException("m must be positive");
+ throw new IllegalArgumentException("m must be positive");
}
if (m > 32)
{
- throw new InvalidParameterException("m is too large");
+ throw new IllegalArgumentException("m is too large");
}
this.m = m;
n = 1 << m;
if (t < 0)
{
- throw new InvalidParameterException("t must be positive");
+ throw new IllegalArgumentException("t must be positive");
}
if (t > n)
{
- throw new InvalidParameterException("t must be less than n = 2^m");
+ throw new IllegalArgumentException("t must be less than n = 2^m");
}
this.t = t;
fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
@@ -115,31 +114,30 @@ public class ECCKeyGenParameterSpec
* @param m degree of the finite field GF(2^m)
* @param t error correction capability of the code
* @param poly the field polynomial
- * @throws InvalidParameterException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * @throws IllegalArgumentException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
* <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
* <tt>poly</tt> is not an irreducible field polynomial.
*/
- public ECCKeyGenParameterSpec(int m, int t, int poly)
- throws InvalidParameterException
+ public McElieceKeyGenParameterSpec(int m, int t, int poly)
{
this.m = m;
if (m < 1)
{
- throw new InvalidParameterException("m must be positive");
+ throw new IllegalArgumentException("m must be positive");
}
if (m > 32)
{
- throw new InvalidParameterException(" m is too large");
+ throw new IllegalArgumentException(" m is too large");
}
this.n = 1 << m;
this.t = t;
if (t < 0)
{
- throw new InvalidParameterException("t must be positive");
+ throw new IllegalArgumentException("t must be positive");
}
if (t > n)
{
- throw new InvalidParameterException("t must be less than n = 2^m");
+ throw new IllegalArgumentException("t must be less than n = 2^m");
}
if ((PolynomialRingGF2.degree(poly) == m)
&& (PolynomialRingGF2.isIrreducible(poly)))
@@ -148,7 +146,7 @@ public class ECCKeyGenParameterSpec
}
else
{
- throw new InvalidParameterException(
+ throw new IllegalArgumentException(
"polynomial is not a field polynomial for GF(2^m)");
}
}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java
deleted file mode 100644
index 8afb2f0e..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java
+++ /dev/null
@@ -1,200 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-
-import java.security.spec.KeySpec;
-
-import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
-import org.bouncycastle.pqc.math.linearalgebra.GF2mField;
-import org.bouncycastle.pqc.math.linearalgebra.Permutation;
-import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
-
-/**
- * This class provides a specification for a McEliece private key.
- *
- * @see KeySpec
- */
-public class McEliecePrivateKeySpec
- implements KeySpec
-{
-
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the dimension of the code, where <tt>k &gt;= n - mt</tt>
- private int k;
-
- // the underlying finite field
- private GF2mField field;
-
- // the irreducible Goppa polynomial
- private PolynomialGF2mSmallM goppaPoly;
-
- // a k x k random binary non-singular matrix
- private GF2Matrix sInv;
-
- // the permutation used to generate the systematic check matrix
- private Permutation p1;
-
- // the permutation used to compute the public generator matrix
- private Permutation p2;
-
- // the canonical check matrix of the code
- private GF2Matrix h;
-
- // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
- private PolynomialGF2mSmallM[] qInv;
-
- /**
- * Constructor.
- *
- * @param oid string representation of the object identifier the algorithm for this key.
- * @param n the length of the code
- * @param k the dimension of the code
- * @param field the field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param goppaPoly the irreducible Goppa polynomial
- * @param sInv the matrix <tt>S<sup>-1</sup></tt>
- * @param p1 the permutation used to generate the systematic check
- * matrix
- * @param p2 the permutation used to compute the public generator
- * matrix
- * @param h the canonical check matrix
- * @param qInv the matrix used to compute square roots in
- * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- */
- public McEliecePrivateKeySpec(String oid, int n, int k, GF2mField field,
- PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
- Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
- {
- this.oid = oid;
- this.k = k;
- this.n = n;
- this.field = field;
- this.goppaPoly = goppaPoly;
- this.sInv = sInv;
- this.p1 = p1;
- this.p2 = p2;
- this.h = h;
- this.qInv = qInv;
- }
-
- /**
- * Constructor.
- *
- * @param oid string representation of the object identifier the algorithm for this key.
- * @param n the length of the code
- * @param k the dimension of the code
- * @param encField the encoded field polynomial defining the finite field
- * <tt>GF(2<sup>m</sup>)</tt>
- * @param encGoppaPoly the encoded irreducible Goppa polynomial
- * @param encSInv the encoded matrix <tt>S<sup>-1</sup></tt>
- * @param encP1 the encoded permutation used to generate the systematic
- * check matrix
- * @param encP2 the encoded permutation used to compute the public
- * generator matrix
- * @param encH the encoded canonical check matrix
- * @param encQInv the encoded matrix used to compute square roots in
- * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- */
- public McEliecePrivateKeySpec(String oid, int n, int k, byte[] encField,
- byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2,
- byte[] encH, byte[][] encQInv)
- {
- this.oid = oid;
- this.n = n;
- this.k = k;
- field = new GF2mField(encField);
- goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
- sInv = new GF2Matrix(encSInv);
- p1 = new Permutation(encP1);
- p2 = new Permutation(encP2);
- h = new GF2Matrix(encH);
- qInv = new PolynomialGF2mSmallM[encQInv.length];
- for (int i = 0; i < encQInv.length; i++)
- {
- qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
- }
- }
-
- /**
- * @return the length of the code
- */
- public int getN()
- {
- return n;
- }
-
- /**
- * @return the dimension of the code
- */
- public int getK()
- {
- return k;
- }
-
- /**
- * @return the finite field <tt>GF(2<sup>m</sup>)</tt>
- */
- public GF2mField getField()
- {
- return field;
- }
-
- /**
- * @return the irreducible Goppa polynomial
- */
- public PolynomialGF2mSmallM getGoppaPoly()
- {
- return goppaPoly;
- }
-
- /**
- * @return the k x k random binary non-singular matrix S^-1
- */
- public GF2Matrix getSInv()
- {
- return sInv;
- }
-
- /**
- * @return the permutation used to generate the systematic check matrix
- */
- public Permutation getP1()
- {
- return p1;
- }
-
- /**
- * @return the permutation used to compute the public generator matrix
- */
- public Permutation getP2()
- {
- return p2;
- }
-
- /**
- * @return the canonical check matrix H
- */
- public GF2Matrix getH()
- {
- return h;
- }
-
- /**
- * @return the matrix used to compute square roots in
- * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
- */
- public PolynomialGF2mSmallM[] getQInv()
- {
- return qInv;
- }
-
- public String getOIDString()
- {
- return oid;
- }
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java
deleted file mode 100644
index f5f18761..00000000
--- a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.bouncycastle.pqc.jcajce.spec;
-
-
-import java.security.spec.KeySpec;
-
-import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix;
-
-/**
- * This class provides a specification for a McEliece public key.
- *
- * @see org.bouncycastle.pqc.jcajce.provider.mceliece.BCMcEliecePublicKey
- */
-public class McEliecePublicKeySpec
- implements KeySpec
-{
-
- // the OID of the algorithm
- private String oid;
-
- // the length of the code
- private int n;
-
- // the error correction capability of the code
- private int t;
-
- // the generator matrix
- private GF2Matrix g;
-
- /**
- * Constructor (used by {@link org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
- *
- * @param oid
- * @param n the length of the code
- * @param t the error correction capability of the code
- * @param g the generator matrix
- */
- public McEliecePublicKeySpec(String oid, int n, int t, GF2Matrix g)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.g = new GF2Matrix(g);
- }
-
- /**
- * Constructor (used by {@link org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
- *
- * @param oid
- * @param n the length of the code
- * @param t the error correction capability of the code
- * @param encG the encoded generator matrix
- */
- public McEliecePublicKeySpec(String oid, int t, int n, byte[] encG)
- {
- this.oid = oid;
- this.n = n;
- this.t = t;
- this.g = new GF2Matrix(encG);
- }
-
- /**
- * @return the length of the code
- */
- public int getN()
- {
- return n;
- }
-
- /**
- * @return the error correction capability of the code
- */
- public int getT()
- {
- return t;
- }
-
- /**
- * @return the generator matrix
- */
- public GF2Matrix getG()
- {
- return g;
- }
-
- public String getOIDString()
- {
- return oid;
-
- }
-
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SPHINCS256KeyGenParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SPHINCS256KeyGenParameterSpec.java
new file mode 100644
index 00000000..fe2fc1a5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SPHINCS256KeyGenParameterSpec.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.pqc.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Key generation spec for SPHINCS-256 to allow specifying of tree hash.
+ */
+public class SPHINCS256KeyGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+ /**
+ * Use SHA512-256 for the tree generation function.
+ */
+ public static final String SHA512_256 = "SHA512-256";
+
+ /**
+ * Use SHA3-256 for the tree generation function.
+ */
+ public static final String SHA3_256 = "SHA3-256";
+
+ private final String treeHash;
+
+ /**
+ * Default constructor SHA512-256
+ */
+ public SPHINCS256KeyGenParameterSpec()
+ {
+ this(SHA512_256);
+ }
+
+ /**
+ * Specify the treehash, one of SHA512-256, or SHA3-256.
+ *
+ * @param treeHash the hash for building the public key tree.
+ */
+ public SPHINCS256KeyGenParameterSpec(String treeHash)
+ {
+ this.treeHash = treeHash;
+ }
+
+ public String getTreeDigest()
+ {
+ return treeHash;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
index 99325a9f..ae609280 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
@@ -103,6 +103,36 @@ public final class Arrays
return true;
}
+ public static boolean areEqual(
+ short[] a,
+ short[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* A constant time equals comparison - does not terminate early if
* test will fail.
@@ -232,6 +262,44 @@ public final class Arrays
return true;
}
+ public static int compareUnsigned(byte[] a, byte[] b)
+ {
+ if (a == b)
+ {
+ return 0;
+ }
+ if (a == null)
+ {
+ return -1;
+ }
+ if (b == null)
+ {
+ return 1;
+ }
+ int minLen = Math.min(a.length, b.length);
+ for (int i = 0; i < minLen; ++i)
+ {
+ int aVal = a[i] & 0xFF, bVal = b[i] & 0xFF;
+ if (aVal < bVal)
+ {
+ return -1;
+ }
+ if (aVal > bVal)
+ {
+ return 1;
+ }
+ }
+ if (a.length < b.length)
+ {
+ return -1;
+ }
+ if (a.length > b.length)
+ {
+ return 1;
+ }
+ return 0;
+ }
+
public static boolean contains(short[] a, short n)
{
for (int i = 0; i < a.length; ++i)
@@ -954,6 +1022,26 @@ public final class Arrays
}
}
+ public static byte[] concatenate(byte[][] arrays)
+ {
+ int size = 0;
+ for (int i = 0; i != arrays.length; i++)
+ {
+ size += arrays[i].length;
+ }
+
+ byte[] rv = new byte[size];
+
+ int offSet = 0;
+ for (int i = 0; i != arrays.length; i++)
+ {
+ System.arraycopy(arrays[i], 0, rv, offSet, arrays[i].length);
+ offSet += arrays[i].length;
+ }
+
+ return rv;
+ }
+
public static int[] concatenate(int[] a, int[] b)
{
if (a == null)
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Pack.java b/bcprov/src/main/java/org/bouncycastle/util/Pack.java
index 94ba17b1..82b02ea5 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/Pack.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/Pack.java
@@ -5,6 +5,13 @@ package org.bouncycastle.util;
*/
public abstract class Pack
{
+ public static short bigEndianToShort(byte[] bs, int off)
+ {
+ int n = (bs[ off] & 0xff) << 8;
+ n |= (bs[++off] & 0xff);
+ return (short)n;
+ }
+
public static int bigEndianToInt(byte[] bs, int off)
{
int n = bs[ off] << 24;
@@ -99,6 +106,13 @@ public abstract class Pack
}
}
+ public static short littleEndianToShort(byte[] bs, int off)
+ {
+ int n = bs[ off] & 0xff;
+ n |= (bs[++off] & 0xff) << 8;
+ return (short)n;
+ }
+
public static int littleEndianToInt(byte[] bs, int off)
{
int n = bs[ off] & 0xff;
@@ -126,6 +140,30 @@ public abstract class Pack
}
}
+ public static int[] littleEndianToInt(byte[] bs, int off, int count)
+ {
+ int[] ns = new int[count];
+ for (int i = 0; i < ns.length; ++i)
+ {
+ ns[i] = littleEndianToInt(bs, off);
+ off += 4;
+ }
+ return ns;
+ }
+
+ public static byte[] shortToLittleEndian(short n)
+ {
+ byte[] bs = new byte[2];
+ shortToLittleEndian(n, bs, 0);
+ return bs;
+ }
+
+ public static void shortToLittleEndian(short n, byte[] bs, int off)
+ {
+ bs[ off] = (byte)(n );
+ bs[++off] = (byte)(n >>> 8);
+ }
+
public static byte[] intToLittleEndian(int n)
{
byte[] bs = new byte[4];
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java b/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java
index f39e026e..adb158f9 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java
@@ -142,4 +142,10 @@ public final class Streams
}
return total;
}
+
+ public static void writeBufTo(ByteArrayOutputStream buf, OutputStream output)
+ throws IOException
+ {
+ buf.writeTo(output);
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java b/bcprov/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java
index 49bd7301..63c7a827 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/test/FixedSecureRandom.java
@@ -2,75 +2,230 @@ package org.bouncycastle.util.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.security.Provider;
import java.security.SecureRandom;
+import org.bouncycastle.util.Pack;
+import org.bouncycastle.util.encoders.Hex;
+
+/**
+ * A secure random that returns pre-seeded data to calls of nextBytes() or generateSeed().
+ */
public class FixedSecureRandom
extends SecureRandom
{
- private byte[] _data;
-
- private int _index;
- private int _intPad;
-
- public FixedSecureRandom(byte[] value)
+ private static java.math.BigInteger REGULAR = new java.math.BigInteger("01020304ffffffff0506070811111111", 16);
+ private static java.math.BigInteger ANDROID = new java.math.BigInteger("1111111105060708ffffffff01020304", 16);
+ private static java.math.BigInteger CLASSPATH = new java.math.BigInteger("3020104ffffffff05060708111111", 16);
+
+ private static final boolean isAndroidStyle;
+ private static final boolean isClasspathStyle;
+ private static final boolean isRegularStyle;
+
+ static
{
- this(false, new byte[][] { value });
+ java.math.BigInteger check1 = new java.math.BigInteger(128, new RandomChecker());
+ java.math.BigInteger check2 = new java.math.BigInteger(120, new RandomChecker());
+
+ isAndroidStyle = check1.equals(ANDROID);
+ isRegularStyle = check1.equals(REGULAR);
+ isClasspathStyle = check2.equals(CLASSPATH);
}
-
- public FixedSecureRandom(
- byte[][] values)
+
+ private byte[] _data;
+ private int _index;
+
+ /**
+ * Base class for sources of fixed "Randomness"
+ */
+ public static class Source
{
- this(false, values);
+ byte[] data;
+
+ Source(byte[] data)
+ {
+ this.data = data;
+ }
}
-
+
/**
- * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger
- * implementation.
+ * Data Source - in this case we just expect requests for byte arrays.
*/
- public FixedSecureRandom(
- boolean intPad,
- byte[] value)
+ public static class Data
+ extends Source
{
- this(intPad, new byte[][] { value });
+ public Data(byte[] data)
+ {
+ super(data);
+ }
}
-
+
/**
- * Pad the data on integer boundaries. This is necessary for the classpath project's BigInteger
- * implementation.
+ * BigInteger Source - in this case we expect requests for data that will be used
+ * for BigIntegers. The FixedSecureRandom will attempt to compensate for platform differences here.
*/
+ public static class BigInteger
+ extends Source
+ {
+ public BigInteger(byte[] data)
+ {
+ super(data);
+ }
+
+ public BigInteger(int bitLength, byte[] data)
+ {
+ super(expandToBitLength(bitLength, data));
+ }
+
+ public BigInteger(String hexData)
+ {
+ this(Hex.decode(hexData));
+ }
+
+ public BigInteger(int bitLength, String hexData)
+ {
+ super(expandToBitLength(bitLength, Hex.decode(hexData)));
+ }
+ }
+
+ public FixedSecureRandom(byte[] value)
+ {
+ this(new Source[] { new Data(value) });
+ }
+
public FixedSecureRandom(
- boolean intPad,
byte[][] values)
{
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
+ this(buildDataArray(values));
+ }
+
+ private static Data[] buildDataArray(byte[][] values)
+ {
+ Data[] res = new Data[values.length];
+
for (int i = 0; i != values.length; i++)
{
- try
+ res[i] = new Data(values[i]);
+ }
+
+ return res;
+ }
+
+ public FixedSecureRandom(
+ Source[] sources)
+ {
+ super(null, new DummyProvider()); // to prevent recursion in provider creation
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ if (isRegularStyle)
+ {
+ if (isClasspathStyle)
{
- bOut.write(values[i]);
+ for (int i = 0; i != sources.length; i++)
+ {
+ try
+ {
+ if (sources[i] instanceof BigInteger)
+ {
+ byte[] data = sources[i].data;
+ int len = data.length - (data.length % 4);
+ for (int w = data.length - len - 1; w >= 0; w--)
+ {
+ bOut.write(data[w]);
+ }
+ for (int w = data.length - len; w < data.length; w += 4)
+ {
+ bOut.write(data, w, 4);
+ }
+ }
+ else
+ {
+ bOut.write(sources[i].data);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't save value source.");
+ }
+ }
}
- catch (IOException e)
+ else
{
- throw new IllegalArgumentException("can't save value array.");
+ for (int i = 0; i != sources.length; i++)
+ {
+ try
+ {
+ bOut.write(sources[i].data);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't save value source.");
+ }
+ }
}
}
-
- _data = bOut.toByteArray();
-
- if (intPad)
+ else if (isAndroidStyle)
+ {
+ for (int i = 0; i != sources.length; i++)
+ {
+ try
+ {
+ if (sources[i] instanceof BigInteger)
+ {
+ byte[] data = sources[i].data;
+ int len = data.length - (data.length % 4);
+ for (int w = 0; w < len; w += 4)
+ {
+ bOut.write(data, data.length - (w + 4), 4);
+ }
+ if (data.length - len != 0)
+ {
+ for (int w = 0; w != 4 - (data.length - len); w++)
+ {
+ bOut.write(0);
+ }
+ }
+ for (int w = 0; w != data.length - len; w++)
+ {
+ bOut.write(data[len + w]);
+ }
+ }
+ else
+ {
+ bOut.write(sources[i].data);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't save value source.");
+ }
+ }
+ }
+ else
{
- _intPad = _data.length % 4;
+ throw new IllegalStateException("Unrecognized BigInteger implementation");
}
+
+ _data = bOut.toByteArray();
}
public void nextBytes(byte[] bytes)
{
System.arraycopy(_data, _index, bytes, 0, bytes.length);
-
+
_index += bytes.length;
}
-
+
+ public byte[] generateSeed(int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+
+ this.nextBytes(bytes);
+
+ return bytes;
+ }
+
//
// classpath's implementation of SecureRandom doesn't currently go back to nextBytes
// when next is called. We can't override next as it's a final method.
@@ -81,25 +236,9 @@ public class FixedSecureRandom
val |= nextValue() << 24;
val |= nextValue() << 16;
-
- if (_intPad == 2)
- {
- _intPad--;
- }
- else
- {
- val |= nextValue() << 8;
- }
-
- if (_intPad == 1)
- {
- _intPad--;
- }
- else
- {
- val |= nextValue();
- }
-
+ val |= nextValue() << 8;
+ val |= nextValue();
+
return val;
}
@@ -132,4 +271,65 @@ public class FixedSecureRandom
{
return _data[_index++] & 0xff;
}
+
+ private static class RandomChecker
+ extends SecureRandom
+ {
+ RandomChecker()
+ {
+ super(null, new DummyProvider()); // to prevent recursion in provider creation
+ }
+
+ byte[] data = Hex.decode("01020304ffffffff0506070811111111");
+ int index = 0;
+
+ public void nextBytes(byte[] bytes)
+ {
+ System.arraycopy(data, index, bytes, 0, bytes.length);
+
+ index += bytes.length;
+ }
+ }
+
+ private static byte[] expandToBitLength(int bitLength, byte[] v)
+ {
+ if ((bitLength + 7) / 8 > v.length)
+ {
+ byte[] tmp = new byte[(bitLength + 7) / 8];
+
+ System.arraycopy(v, 0, tmp, tmp.length - v.length, v.length);
+ if (isAndroidStyle)
+ {
+ if (bitLength % 8 != 0)
+ {
+ int i = Pack.bigEndianToInt(tmp, 0);
+ Pack.intToBigEndian(i << (8 - (bitLength % 8)), tmp, 0);
+ }
+ }
+
+ return tmp;
+ }
+ else
+ {
+ if (isAndroidStyle && bitLength < (v.length * 8))
+ {
+ if (bitLength % 8 != 0)
+ {
+ int i = Pack.bigEndianToInt(v, 0);
+ Pack.intToBigEndian(i << (8 - (bitLength % 8)), v, 0);
+ }
+ }
+ }
+
+ return v;
+ }
+
+ private static class DummyProvider
+ extends Provider
+ {
+ DummyProvider()
+ {
+ super("BCFIPS_FIXED_RNG", 1.0, "BCFIPS Fixed Secure Random Provider");
+ }
+ }
}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/test/SimpleTest.java b/bcprov/src/main/java/org/bouncycastle/util/test/SimpleTest.java
index ef8ee617..dd182350 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/test/SimpleTest.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/test/SimpleTest.java
@@ -19,6 +19,16 @@ public abstract class SimpleTest
{
throw new TestFailedException(SimpleTestResult.failed(this, message));
}
+
+ protected void isTrue(
+ String message,
+ boolean value)
+ {
+ if (!value)
+ {
+ throw new TestFailedException(SimpleTestResult.failed(this, message));
+ }
+ }
protected void fail(
String message,
diff --git a/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java b/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java
new file mode 100644
index 00000000..db27989a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomBigInteger.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.util.test;
+
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * A fixed secure random designed to return data for someone needing to create a single BigInteger.
+ */
+public class TestRandomBigInteger
+ extends FixedSecureRandom
+{
+ /**
+ * Constructor from a base 10 represention of a BigInteger.
+ *
+ * @param encoding a base 10 represention of a BigInteger.
+ */
+ public TestRandomBigInteger(String encoding)
+ {
+ this(encoding, 10);
+ }
+
+ /**
+ * Constructor from a base radix represention of a BigInteger.
+ *
+ * @param encoding a String BigInteger of base radix.
+ * @param radix the radix to use.
+ */
+ public TestRandomBigInteger(String encoding, int radix)
+ {
+ super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new java.math.BigInteger(encoding, radix))) });
+ }
+
+ /**
+ * Constructor based on a byte array.
+ *
+ * @param encoding a 2's complement representation of the BigInteger.
+ */
+ public TestRandomBigInteger(byte[] encoding)
+ {
+ super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(encoding) });
+ }
+
+ /**
+ * Constructor which ensures encoding will produce a BigInteger from a request from the passed in bitLength.
+ *
+ * @param bitLength bit length for the BigInteger data request.
+ * @param encoding bytes making up the encoding.
+ */
+ public TestRandomBigInteger(int bitLength, byte[] encoding)
+ {
+ super(new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(bitLength, encoding) });
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomData.java b/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomData.java
new file mode 100644
index 00000000..e069041c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/test/TestRandomData.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.util.test;
+
+import org.bouncycastle.util.encoders.Hex;
+
+/**
+ * A fixed secure random designed to return data for someone needing random bytes.
+ */
+public class TestRandomData
+ extends FixedSecureRandom
+{
+ /**
+ * Constructor from a Hex encoding of the data.
+ *
+ * @param encoding a Hex encoding of the data to be returned.
+ */
+ public TestRandomData(String encoding)
+ {
+ super(new Source[] { new FixedSecureRandom.Data(Hex.decode(encoding)) });
+ }
+
+ /**
+ * Constructor from an array of bytes.
+ *
+ * @param encoding a byte array representing the data to be returned.
+ */
+ public TestRandomData(byte[] encoding)
+ {
+ super(new Source[] { new FixedSecureRandom.Data(encoding) });
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509CertificatePair.java b/bcprov/src/main/java/org/bouncycastle/x509/X509CertificatePair.java
index 73e5ba31..d864b71c 100644
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509CertificatePair.java
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509CertificatePair.java
@@ -9,6 +9,8 @@ import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificatePair;
+import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.provider.X509CertificateObject;
/**
@@ -19,9 +21,12 @@ import org.bouncycastle.jce.provider.X509CertificateObject;
*/
public class X509CertificatePair
{
+ private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+
private X509Certificate forward;
private X509Certificate reverse;
+ // TODO: should get rid of this class
/**
* Constructor.
*
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
index 01f4469f..5833d17e 100644
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -1,5 +1,6 @@
package org.bouncycastle.x509;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
@@ -11,7 +12,6 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Iterator;
@@ -19,19 +19,21 @@ import java.util.Iterator;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
+import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.jce.provider.X509CertificateObject;
/**
* class to produce an X.509 Version 1 certificate.
@@ -39,6 +41,9 @@ import org.bouncycastle.jce.provider.X509CertificateObject;
*/
public class X509V1CertificateGenerator
{
+ private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+ private final CertificateFactory certificateFactory = new CertificateFactory();
+
private V1TBSCertificateGenerator tbsGen;
private ASN1ObjectIdentifier sigOID;
private AlgorithmIdentifier sigAlgId;
@@ -353,9 +358,10 @@ public class X509V1CertificateGenerator
try
{
- return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ return (X509Certificate)certificateFactory.engineGenerateCertificate(
+ new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
}
- catch (CertificateParsingException e)
+ catch (Exception e)
{
throw new ExtCertificateEncodingException("exception producing certificate object", e);
}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java
index 8773d0ec..0bbaf4fe 100644
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java
@@ -36,6 +36,8 @@ import org.bouncycastle.asn1.x509.V2TBSCertListGenerator;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.provider.X509CRLObject;
@@ -45,6 +47,8 @@ import org.bouncycastle.jce.provider.X509CRLObject;
*/
public class X509V2CRLGenerator
{
+ private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+
private V2TBSCertListGenerator tbsGen;
private ASN1ObjectIdentifier sigOID;
private AlgorithmIdentifier sigAlgId;
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
index c422cb26..325b8fbc 100644
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -1,5 +1,6 @@
package org.bouncycastle.x509;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
@@ -20,21 +21,23 @@ import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
+import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.jce.provider.X509CertificateObject;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
/**
@@ -43,6 +46,9 @@ import org.bouncycastle.x509.extension.X509ExtensionUtil;
*/
public class X509V3CertificateGenerator
{
+ private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+ private final CertificateFactory certificateFactory = new CertificateFactory();
+
private V3TBSCertificateGenerator tbsGen;
private ASN1ObjectIdentifier sigOID;
private AlgorithmIdentifier sigAlgId;
@@ -441,7 +447,7 @@ public class X509V3CertificateGenerator
{
return generateJcaObject(tbsCert, signature);
}
- catch (CertificateParsingException e)
+ catch (Exception e)
{
throw new ExtCertificateEncodingException("exception producing certificate object", e);
}
@@ -486,7 +492,7 @@ public class X509V3CertificateGenerator
{
return generateJcaObject(tbsCert, signature);
}
- catch (CertificateParsingException e)
+ catch (Exception e)
{
throw new ExtCertificateEncodingException("exception producing certificate object", e);
}
@@ -503,7 +509,7 @@ public class X509V3CertificateGenerator
}
private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
- throws CertificateParsingException
+ throws Exception
{
ASN1EncodableVector v = new ASN1EncodableVector();
@@ -511,7 +517,8 @@ public class X509V3CertificateGenerator
v.add(sigAlgId);
v.add(new DERBitString(signature));
- return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ return (X509Certificate)certificateFactory.engineGenerateCertificate(
+ new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
}
/**
diff --git a/bouncycastle.version b/bouncycastle.version
index 00639910..c7e252d8 100644
--- a/bouncycastle.version
+++ b/bouncycastle.version
@@ -1,2 +1,2 @@
BOUNCYCASTLE_JDK=15on
-BOUNCYCASTLE_VERSION=154
+BOUNCYCASTLE_VERSION=156